1 //this file is part of MimeTools (plugin for Notepad++) 2 //Copyright (C)2019 Don HO <don.h@free.fr> 3 // 4 // 5 // Enhance Base64 features, and rewrite Base64 encode/decode implementation 6 // Copyright 2019 by Paul Nankervis <paulnank@hotmail.com> 7 // 8 // 9 //This program is free software; you can redistribute it and/or 10 //modify it under the terms of the GNU General Public License 11 //as published by the Free Software Foundation; either 12 //version 2 of the License, or (at your option) any later version. 13 // 14 //This program is distributed in the hope that it will be useful, 15 //but WITHOUT ANY WARRANTY; without even the implied warranty of 16 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 //GNU General Public License for more details. 18 // 19 //You should have received a copy of the GNU General Public License 20 //along with this program; if not, write to the Free Software 21 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 module npp_mimetools.mimeTools; 23 24 25 private static import core.stdc.string; 26 private static import core.sys.windows.basetsd; 27 private static import core.sys.windows.winbase; 28 private static import core.sys.windows.windef; 29 private static import core.sys.windows.winnt; 30 private static import core.sys.windows.winuser; 31 private static import npp_api.PowerEditor.MISC.PluginsManager.PluginInterface; 32 private static import npp_api.pluginfunc.basic_interface; 33 private static import npp_api.pluginfunc.npp_msgs; 34 private static import npp_api.pluginfunc.scintilla_msg; 35 private static import npp_api.pluginfunc.string; 36 private static import npp_mimetools.b64; 37 private static import npp_mimetools.qp; 38 private static import npp_mimetools.saml; 39 private static import npp_mimetools.url; 40 41 enum IDD_ABOUTBOX = 250; 42 enum IDC_STATIC = -1; 43 44 enum PLUGIN_NAME = npp_api.pluginfunc..string.c_wstring!(`MIME Tools Sample`); 45 46 core.sys.windows.windef.HINSTANCE _hInst; 47 48 enum npp_api.PowerEditor.MISC.PluginsManager.PluginInterface.FuncItem[] main_menu_items_def = 49 [ 50 { 51 _itemName: `Base64 Encode`w, 52 _pFunc: &.convertToBase64FromAscii, 53 _init2Check: false, 54 _pShKey: null, 55 }, 56 { 57 _itemName: `Base64 Encode with padding`w, 58 _pFunc: &.convertToBase64FromAscii_pad, 59 _init2Check: false, 60 _pShKey: null, 61 }, 62 { 63 _itemName: `Base64 Encode with Unix EOL`w, 64 _pFunc: &.convertToBase64FromAscii_B64Format, 65 _init2Check: false, 66 _pShKey: null, 67 }, 68 { 69 _itemName: `Base64 Encode by line`w, 70 _pFunc: &.convertToBase64FromAscii_byline, 71 _init2Check: false, 72 _pShKey: null, 73 }, 74 { 75 _itemName: `Base64 Decode`w, 76 _pFunc: &.convertToAsciiFromBase64, 77 _init2Check: false, 78 _pShKey: null, 79 }, 80 { 81 _itemName: `Base64 Decode strict`w, 82 _pFunc: &.convertToAsciiFromBase64_strict, 83 _init2Check: false, 84 _pShKey: null, 85 }, 86 { 87 _itemName: `Base64 Decode by line`w, 88 _pFunc: &.convertToAsciiFromBase64_whitespaceReset, 89 _init2Check: false, 90 _pShKey: null, 91 }, 92 { 93 _pFunc: null, 94 }, 95 { 96 _itemName: `Quoted-printable Encode`w, 97 _pFunc: &.convertToQuotedPrintable, 98 _init2Check: false, 99 _pShKey: null, 100 }, 101 { 102 _itemName: `Quoted-printable Decode`w, 103 _pFunc: &.convertToAsciiFromQuotedPrintable, 104 _init2Check: false, 105 _pShKey: null, 106 }, 107 { 108 _pFunc: null, 109 }, 110 { 111 _itemName: `URL Encode`w, 112 _pFunc: &.convertURLMinEncode, 113 _init2Check: false, 114 _pShKey: null, 115 }, 116 { 117 _itemName: `Full URL Encode`w, 118 _pFunc: &.convertURLFullEncode, 119 _init2Check: false, 120 _pShKey: null, 121 }, 122 { 123 _itemName: `URL Decode`w, 124 _pFunc: &.convertURLDecode, 125 _init2Check: false, 126 _pShKey: null, 127 }, 128 { 129 _pFunc: null, 130 }, 131 { 132 _itemName: `SAML Decode`w, 133 _pFunc: &.convertSamlDecode, 134 _init2Check: false, 135 _pShKey: null, 136 }, 137 { 138 _pFunc: null, 139 }, 140 { 141 _itemName: `About`w, 142 _pFunc: &.about, 143 _init2Check: false, 144 _pShKey: null, 145 }, 146 ]; 147 148 nothrow @nogc 149 core.sys.windows.windef.HWND getCurrentScintillaHandle() 150 151 do 152 { 153 int currentEdit; 154 npp_api.pluginfunc.npp_msgs.send_NPPM_GETCURRENTSCINTILLA(nppData._nppHandle, currentEdit); 155 156 return (currentEdit == 0) ? (nppData._scintillaMainHandle) : (nppData._scintillaSecondHandle); 157 } 158 159 nothrow 160 void convertAsciiToBase64(size_t wrapLength, bool padFlag, bool byLineFlag) 161 162 do 163 { 164 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 165 size_t selectedLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 166 167 if (selectedLength == 0) { 168 return; 169 } 170 171 char[] selectedText = new char[selectedLength]; 172 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 173 npp_api.pluginfunc.scintilla_msg.send_SCI_GETTARGETTEXT(hCurrScintilla, &(selectedText[0])); 174 175 size_t bufferLength = (selectedLength + 2) / 3 * 4 + 1; 176 177 if (wrapLength > 0) { 178 bufferLength += bufferLength / wrapLength; 179 } 180 181 char[] encodedText = new char[bufferLength + 1]; 182 183 int len = npp_mimetools.b64.base64Encode(encodedText, selectedText, selectedLength - 1, wrapLength, padFlag, byLineFlag); 184 encodedText[len] = '\0'; 185 186 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 187 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(encodedText[0])); 188 } 189 190 extern (C) 191 nothrow 192 void convertToBase64FromAscii() 193 194 do 195 { 196 .convertAsciiToBase64(0, false, false); 197 } 198 199 extern (C) 200 nothrow 201 void convertToBase64FromAscii_pad() 202 203 do 204 { 205 .convertAsciiToBase64(0, true, false); 206 } 207 208 extern (C) 209 nothrow 210 void convertToBase64FromAscii_B64Format() 211 212 do 213 { 214 .convertAsciiToBase64(64, true, false); 215 } 216 217 extern (C) 218 nothrow 219 void convertToBase64FromAscii_byline() 220 221 do 222 { 223 .convertAsciiToBase64(0, false, true); 224 } 225 226 nothrow 227 void convertBase64ToAscii(bool strictFlag, bool whitespaceReset) 228 229 do 230 { 231 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 232 size_t selectedLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 233 234 if (selectedLength == 0) { 235 return; 236 } 237 238 char[] selectedText = new char[selectedLength]; 239 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 240 npp_api.pluginfunc.scintilla_msg.send_SCI_GETTARGETTEXT(hCurrScintilla, &(selectedText[0])); 241 242 char[] decodedText = new char[selectedLength]; 243 244 int len = npp_mimetools.b64.base64Decode(decodedText, selectedText, selectedLength - 1, strictFlag, whitespaceReset); 245 246 if (len < 0) { 247 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Problem!`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`Base64`)[0]), core.sys.windows.winuser.MB_OK); 248 } else { 249 decodedText[len] = '\0'; 250 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 251 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(decodedText[0])); 252 } 253 } 254 255 extern (C) 256 nothrow 257 void convertToAsciiFromBase64() 258 259 do 260 { 261 .convertBase64ToAscii(false, false); 262 } 263 264 extern (C) 265 nothrow 266 void convertToAsciiFromBase64_strict() 267 268 do 269 { 270 .convertBase64ToAscii(true, false); 271 } 272 273 extern (C) 274 nothrow 275 void convertToAsciiFromBase64_whitespaceReset() 276 277 do 278 { 279 .convertBase64ToAscii(false, true); 280 } 281 282 extern (C) 283 nothrow 284 void convertURLMinEncode() 285 286 do 287 { 288 .convertURLEncode(false); 289 } 290 291 extern (C) 292 nothrow 293 void convertURLFullEncode() 294 295 do 296 { 297 .convertURLEncode(true); 298 } 299 300 nothrow 301 void convertURLEncode(bool encodeAll) 302 303 do 304 { 305 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 306 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 307 308 if (bufLength == 0) { 309 return; 310 } 311 312 char[] selectedText = new char[bufLength]; 313 char[] pEncodedText = new char[bufLength * 3]; 314 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 315 316 size_t len = npp_mimetools.url.AsciiToUrl(pEncodedText, selectedText, encodeAll); 317 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 318 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 319 320 if (end < start) { 321 size_t tmp = start; 322 start = end; 323 end = tmp; 324 } 325 326 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 327 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 328 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(pEncodedText[0])); 329 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len); 330 } 331 332 extern (C) 333 nothrow 334 void convertURLDecode() 335 336 do 337 { 338 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 339 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 340 341 if (bufLength == 0) { 342 return; 343 } 344 345 char[] selectedText = new char[bufLength]; 346 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 347 char[] pDecodedText = new char[bufLength]; 348 349 size_t len = npp_mimetools.url.UrlToAscii(pDecodedText, selectedText); 350 351 if (len == 0) { 352 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Encoding Invalid!`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`URL Decode`)[0]), core.sys.windows.winuser.MB_OK); 353 } else { 354 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 355 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 356 357 if (end < start) { 358 size_t tmp = start; 359 start = end; 360 end = tmp; 361 } 362 363 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 364 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 365 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(pDecodedText[0])); 366 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len); 367 } 368 } 369 370 enum qpOp 371 { 372 qp_encode, 373 qp_decode, 374 } 375 376 nothrow 377 void quotedPrintableConvert(.qpOp op) 378 379 do 380 { 381 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 382 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 383 384 if (bufLength == 0) { 385 return; 386 } 387 388 char[] selectedText = new char[bufLength]; 389 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 390 391 string qpText; 392 npp_mimetools.qp.QuotedPrintable qp; 393 394 if (op == .qpOp.qp_decode) { 395 qpText = qp.decode(selectedText); 396 397 if (qpText == null) { 398 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`It's not a valid Quoted-printable text`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`Quoted-printable decode error`)[0]), core.sys.windows.winuser.MB_OK); 399 400 return; 401 } 402 } else { 403 qpText = qp.encode(selectedText); 404 } 405 406 if (qpText == null) { 407 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Problem!`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`Quoted-printable encoding`)[0]), core.sys.windows.winuser.MB_OK); 408 } else { 409 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 410 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 411 412 if (end < start) { 413 size_t tmp = start; 414 start = end; 415 end = tmp; 416 } 417 418 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 419 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 420 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, core.stdc..string.strlen(&(qpText[0])), &(qpText[0])); 421 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + core.stdc..string.strlen(&(qpText[0]))); 422 } 423 } 424 425 extern (C) 426 nothrow 427 void convertToAsciiFromQuotedPrintable() 428 429 do 430 { 431 .quotedPrintableConvert(.qpOp.qp_decode); 432 } 433 434 extern (C) 435 nothrow 436 void convertToQuotedPrintable() 437 438 do 439 { 440 .quotedPrintableConvert(.qpOp.qp_encode); 441 } 442 443 extern (Windows) 444 nothrow @nogc 445 core.sys.windows.windef.BOOL dlgProc(core.sys.windows.windef.HWND hwnd, core.sys.windows.windef.UINT message, core.sys.windows.windef.WPARAM wParam, core.sys.windows.windef.LPARAM lParam) 446 447 do 448 { 449 switch (message) { 450 case core.sys.windows.winuser.WM_COMMAND: 451 switch (core.sys.windows.windef.LOWORD(wParam)) { 452 case core.sys.windows.winuser.IDCLOSE: 453 core.sys.windows.winuser.EndDialog(hwnd, 0); 454 455 return core.sys.windows.windef.TRUE; 456 457 default: 458 break; 459 } 460 461 return core.sys.windows.windef.FALSE; 462 463 default: 464 break; 465 } 466 467 return core.sys.windows.windef.FALSE; 468 } 469 470 extern (C) 471 nothrow @nogc 472 void about() 473 474 do 475 { 476 core.sys.windows.windef.HWND hSelf = core.sys.windows.winuser.CreateDialogParamW(_hInst, core.sys.windows.winuser.MAKEINTRESOURCEW(.IDD_ABOUTBOX), nppData._nppHandle, cast(core.sys.windows.winuser.DLGPROC)(&.dlgProc), 0); 477 478 // Go to center 479 core.sys.windows.windef.RECT rc; 480 core.sys.windows.winuser.GetClientRect(nppData._nppHandle, &rc); 481 core.sys.windows.windef.POINT center; 482 int w = rc.right - rc.left; 483 int h = rc.bottom - rc.top; 484 center.x = rc.left + w / 2; 485 center.y = rc.top + h / 2; 486 core.sys.windows.winuser.ClientToScreen(nppData._nppHandle, ¢er); 487 488 core.sys.windows.windef.RECT dlgRect; 489 core.sys.windows.winuser.GetClientRect(hSelf, &dlgRect); 490 int x = center.x - (dlgRect.right - dlgRect.left) / 2; 491 int y = center.y - (dlgRect.bottom - dlgRect.top) / 2; 492 493 core.sys.windows.winuser.SetWindowPos(hSelf, core.sys.windows.winuser.HWND_TOP, x, y, (dlgRect.right - dlgRect.left), (dlgRect.bottom - dlgRect.top), core.sys.windows.winuser.SWP_SHOWWINDOW); 494 } 495 496 extern (C) 497 nothrow 498 void convertSamlDecode() 499 500 do 501 { 502 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 503 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 504 505 if (bufLength == 0) { 506 return; 507 } 508 509 char[] selectedText = new char[bufLength]; 510 char[] samlDecodedText = new char[npp_mimetools.saml.SAML_MESSAGE_MAX_SIZE]; 511 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 512 513 int len = npp_mimetools.saml.samlDecode(samlDecodedText, selectedText); 514 515 switch (len) { 516 case 0: 517 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode returned zero size.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK); 518 519 break; 520 521 case npp_mimetools.saml.SAML_DECODE_ERROR_URLDECODE: 522 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Could not URL Decode text.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK); 523 524 break; 525 526 case npp_mimetools.saml.SAML_DECODE_ERROR_BASE64DECODE: 527 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Could not BASE64 Decode text after URL Decoding.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK); 528 529 break; 530 531 case npp_mimetools.saml.SAML_DECODE_ERROR_INFLATE: 532 core.sys.windows.winuser.MessageBoxW(nppData._nppHandle, &(npp_api.pluginfunc..string.c_wstring!(`Could not inflate text after BASE64 Decoding.`)[0]), &(npp_api.pluginfunc..string.c_wstring!(`SAML Decode`)[0]), core.sys.windows.winuser.MB_OK); 533 534 break; 535 536 default: 537 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 538 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 539 540 if (end < start) { 541 size_t tmp = start; 542 start = end; 543 end = tmp; 544 } 545 546 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 547 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 548 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(samlDecodedText[0])); 549 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len); 550 } 551 } 552 553 mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(PLUGIN_NAME, .main_menu_items_def);