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.pluginfunc.basic_interface; 32 private static import npp_api.pluginfunc.npp_msgs; 33 private static import npp_api.pluginfunc.scintilla_msg; 34 private static import npp_api.pluginfunc.string; 35 private static import npp_api.powereditor.misc.pluginsmanager.plugininterface; 36 private static import npp_mimetools.b64; 37 private static import npp_mimetools.qp; 38 private static import npp_mimetools.url; 39 private static import npp_mimetools.saml; 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 static import npp_api.pluginfunc.npp_msgs; 154 155 int currentEdit; 156 npp_api.pluginfunc.npp_msgs.send_NPPM_GETCURRENTSCINTILLA(nppData._nppHandle, currentEdit); 157 158 return (currentEdit == 0) ? (nppData._scintillaMainHandle) : (nppData._scintillaSecondHandle); 159 } 160 161 nothrow 162 void convertAsciiToBase64(size_t wrapLength, bool padFlag, bool byLineFlag) 163 164 do 165 { 166 static import core.sys.windows.windef; 167 static import npp_api.pluginfunc.scintilla_msg; 168 static import npp_mimetools.b64; 169 170 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 171 size_t selectedLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 172 173 if (selectedLength == 0) { 174 return; 175 } 176 177 char[] selectedText = new char[selectedLength]; 178 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 179 npp_api.pluginfunc.scintilla_msg.send_SCI_GETTARGETTEXT(hCurrScintilla, &(selectedText[0])); 180 181 size_t bufferLength = (selectedLength + 2) / 3 * 4 + 1; 182 183 if (wrapLength > 0) { 184 bufferLength += bufferLength / wrapLength; 185 } 186 187 char[] encodedText = new char[bufferLength + 1]; 188 189 int len = npp_mimetools.b64.base64Encode(encodedText, selectedText, selectedLength - 1, wrapLength, padFlag, byLineFlag); 190 encodedText[len] = '\0'; 191 192 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 193 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(encodedText[0])); 194 } 195 196 extern (C) 197 nothrow 198 void convertToBase64FromAscii() 199 200 do 201 { 202 .convertAsciiToBase64(0, false, false); 203 } 204 205 extern (C) 206 nothrow 207 void convertToBase64FromAscii_pad() 208 209 do 210 { 211 .convertAsciiToBase64(0, true, false); 212 } 213 214 extern (C) 215 nothrow 216 void convertToBase64FromAscii_B64Format() 217 218 do 219 { 220 .convertAsciiToBase64(64, true, false); 221 } 222 223 extern (C) 224 nothrow 225 void convertToBase64FromAscii_byline() 226 227 do 228 { 229 .convertAsciiToBase64(0, false, true); 230 } 231 232 nothrow 233 void convertBase64ToAscii(bool strictFlag, bool whitespaceReset) 234 235 do 236 { 237 static import core.sys.windows.windef; 238 static import core.sys.windows.winuser; 239 static import npp_api.pluginfunc.scintilla_msg; 240 static import npp_api.pluginfunc.string; 241 static import npp_mimetools.b64; 242 243 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 244 size_t selectedLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 245 246 if (selectedLength == 0) { 247 return; 248 } 249 250 char[] selectedText = new char[selectedLength]; 251 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 252 npp_api.pluginfunc.scintilla_msg.send_SCI_GETTARGETTEXT(hCurrScintilla, &(selectedText[0])); 253 254 char[] decodedText = new char[selectedLength]; 255 256 int len = npp_mimetools.b64.base64Decode(decodedText, selectedText, selectedLength - 1, strictFlag, whitespaceReset); 257 258 if (len < 0) { 259 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); 260 } else { 261 decodedText[len] = '\0'; 262 npp_api.pluginfunc.scintilla_msg.send_SCI_TARGETFROMSELECTION(hCurrScintilla); 263 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(decodedText[0])); 264 } 265 } 266 267 extern (C) 268 nothrow 269 void convertToAsciiFromBase64() 270 271 do 272 { 273 .convertBase64ToAscii(false, false); 274 } 275 276 extern (C) 277 nothrow 278 void convertToAsciiFromBase64_strict() 279 280 do 281 { 282 .convertBase64ToAscii(true, false); 283 } 284 285 extern (C) 286 nothrow 287 void convertToAsciiFromBase64_whitespaceReset() 288 289 do 290 { 291 .convertBase64ToAscii(false, true); 292 } 293 294 extern (C) 295 nothrow 296 void convertURLMinEncode() 297 298 do 299 { 300 .convertURLEncode(false); 301 } 302 303 extern (C) 304 nothrow 305 void convertURLFullEncode() 306 307 do 308 { 309 .convertURLEncode(true); 310 } 311 312 nothrow 313 void convertURLEncode(bool encodeAll) 314 315 do 316 { 317 static import core.stdc.string; 318 static import core.sys.windows.windef; 319 static import npp_api.pluginfunc.scintilla_msg; 320 static import npp_mimetools.url; 321 322 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 323 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 324 325 if (bufLength == 0) { 326 return; 327 } 328 329 char[] selectedText = new char[bufLength]; 330 char[] pEncodedText = new char[bufLength * 3]; 331 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 332 333 size_t len = npp_mimetools.url.AsciiToUrl(pEncodedText, selectedText, encodeAll); 334 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 335 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 336 337 if (end < start) { 338 size_t tmp = start; 339 start = end; 340 end = tmp; 341 } 342 343 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 344 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 345 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(pEncodedText[0])); 346 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len); 347 } 348 349 extern (C) 350 nothrow 351 void convertURLDecode() 352 353 do 354 { 355 static import core.stdc.string; 356 static import core.sys.windows.windef; 357 static import core.sys.windows.winuser; 358 static import npp_api.pluginfunc.scintilla_msg; 359 static import npp_api.pluginfunc.string; 360 static import npp_mimetools.url; 361 362 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 363 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 364 365 if (bufLength == 0) { 366 return; 367 } 368 369 char[] selectedText = new char[bufLength]; 370 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 371 char[] pDecodedText = new char[bufLength]; 372 373 size_t len = npp_mimetools.url.UrlToAscii(pDecodedText, selectedText); 374 375 if (len == 0) { 376 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); 377 } else { 378 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 379 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 380 381 if (end < start) { 382 size_t tmp = start; 383 start = end; 384 end = tmp; 385 } 386 387 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 388 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 389 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(pDecodedText[0])); 390 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len); 391 } 392 } 393 394 enum qpOp 395 { 396 qp_encode, 397 qp_decode, 398 } 399 400 nothrow 401 void quotedPrintableConvert(.qpOp op) 402 403 do 404 { 405 static import core.stdc.string; 406 static import core.sys.windows.windef; 407 static import core.sys.windows.winuser; 408 static import npp_api.pluginfunc.scintilla_msg; 409 static import npp_api.pluginfunc.string; 410 static import npp_mimetools.qp; 411 412 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 413 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 414 415 if (bufLength == 0) { 416 return; 417 } 418 419 char[] selectedText = new char[bufLength]; 420 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 421 422 string qpText; 423 npp_mimetools.qp.QuotedPrintable qp; 424 425 if (op == .qpOp.qp_decode) { 426 qpText = qp.decode(selectedText); 427 428 if (qpText == null) { 429 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); 430 431 return; 432 } 433 } else { 434 qpText = qp.encode(selectedText); 435 } 436 437 if (qpText == null) { 438 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); 439 } else { 440 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 441 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 442 443 if (end < start) { 444 size_t tmp = start; 445 start = end; 446 end = tmp; 447 } 448 449 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 450 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 451 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, core.stdc..string.strlen(&(qpText[0])), &(qpText[0])); 452 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + core.stdc..string.strlen(&(qpText[0]))); 453 } 454 } 455 456 extern (C) 457 nothrow 458 void convertToAsciiFromQuotedPrintable() 459 460 do 461 { 462 .quotedPrintableConvert(.qpOp.qp_decode); 463 } 464 465 extern (C) 466 nothrow 467 void convertToQuotedPrintable() 468 469 do 470 { 471 .quotedPrintableConvert(.qpOp.qp_encode); 472 } 473 474 extern (Windows) 475 nothrow @nogc 476 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) 477 478 do 479 { 480 static import core.sys.windows.windef; 481 static import core.sys.windows.winuser; 482 483 switch (message) { 484 case core.sys.windows.winuser.WM_COMMAND: 485 switch (core.sys.windows.windef.LOWORD(wParam)) { 486 case core.sys.windows.winuser.IDCLOSE: 487 core.sys.windows.winuser.EndDialog(hwnd, 0); 488 489 return core.sys.windows.windef.TRUE; 490 491 default: 492 break; 493 } 494 495 return core.sys.windows.windef.FALSE; 496 497 default: 498 break; 499 } 500 501 return core.sys.windows.windef.FALSE; 502 } 503 504 extern (C) 505 nothrow @nogc 506 void about() 507 508 do 509 { 510 static import core.sys.windows.windef; 511 static import core.sys.windows.winuser; 512 513 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); 514 515 // Go to center 516 core.sys.windows.windef.RECT rc; 517 core.sys.windows.winuser.GetClientRect(nppData._nppHandle, &rc); 518 core.sys.windows.windef.POINT center; 519 int w = rc.right - rc.left; 520 int h = rc.bottom - rc.top; 521 center.x = rc.left + w / 2; 522 center.y = rc.top + h / 2; 523 core.sys.windows.winuser.ClientToScreen(nppData._nppHandle, ¢er); 524 525 core.sys.windows.windef.RECT dlgRect; 526 core.sys.windows.winuser.GetClientRect(hSelf, &dlgRect); 527 int x = center.x - (dlgRect.right - dlgRect.left) / 2; 528 int y = center.y - (dlgRect.bottom - dlgRect.top) / 2; 529 530 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); 531 } 532 533 extern (C) 534 nothrow 535 void convertSamlDecode() 536 537 do 538 { 539 static import core.stdc.string; 540 static import core.sys.windows.windef; 541 static import core.sys.windows.winuser; 542 static import npp_api.pluginfunc.scintilla_msg; 543 static import npp_api.pluginfunc.string; 544 545 core.sys.windows.windef.HWND hCurrScintilla = .getCurrentScintillaHandle(); 546 size_t bufLength = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla); 547 548 if (bufLength == 0) { 549 return; 550 } 551 552 char[] selectedText = new char[bufLength]; 553 char[] samlDecodedText = new char[npp_mimetools.saml.SAML_MESSAGE_MAX_SIZE]; 554 npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELTEXT(hCurrScintilla, &(selectedText[0])); 555 556 int len = npp_mimetools.saml.samlDecode(samlDecodedText, selectedText); 557 558 switch (len) { 559 case 0: 560 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); 561 562 break; 563 564 case npp_mimetools.saml.SAML_DECODE_ERROR_URLDECODE: 565 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); 566 567 break; 568 569 case npp_mimetools.saml.SAML_DECODE_ERROR_BASE64DECODE: 570 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); 571 572 break; 573 574 case npp_mimetools.saml.SAML_DECODE_ERROR_INFLATE: 575 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); 576 577 break; 578 579 default: 580 size_t start = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONSTART(hCurrScintilla); 581 size_t end = npp_api.pluginfunc.scintilla_msg.send_SCI_GETSELECTIONEND(hCurrScintilla); 582 583 if (end < start) { 584 size_t tmp = start; 585 start = end; 586 end = tmp; 587 } 588 589 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETSTART(hCurrScintilla, start); 590 npp_api.pluginfunc.scintilla_msg.send_SCI_SETTARGETEND(hCurrScintilla, end); 591 npp_api.pluginfunc.scintilla_msg.send_SCI_REPLACETARGET(hCurrScintilla, len, &(samlDecodedText[0])); 592 npp_api.pluginfunc.scintilla_msg.send_SCI_SETSEL(hCurrScintilla, start, start + len); 593 } 594 } 595 596 mixin npp_api.pluginfunc.basic_interface.npp_plugin_interface!(PLUGIN_NAME, .main_menu_items_def);