source: trunk/src/cppbase/bs_config.cpp@ 369

Last change on this file since 369 was 369, checked in by pr, 17 years ago

No error if WPS object being deleted no longer exists. Bug 1062.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 80.3 KB
Line 
1
2/*
3 *@@sourcefile bs_config.cpp:
4 * this has the code for the classes which manipulate CONFIG.SYS,
5 * the WPS class list, create WPS objects, or do other
6 * WarpIN system configuration.
7 *
8 * These classes are designed to work independently of WarpIN
9 * and could be used in any program.
10 * I have attempted to design these classes for easy, yet flexible use.
11 *
12 * All system config classes are derived from BSConfigBase.
13 * This allows for maintaining a list of all system changes
14 * with each WarpIN package, which have a somewhat uniform
15 * interface. Each config class has in turn a special method
16 * which will actually perform the system configuration change.
17 *
18 * This special method will usually take a logger instance
19 * as a parameter, which logs the changes that were actually
20 * made to the system. This logger can then be used later to
21 * undo the change.
22 * See BSCfgSysManip::BSCfgSysManip for an example usage.
23 *
24 * The loggers are all direct, unmodified descendants of the
25 * BSMemLoggerBase class (bs_logger.cpp) and only defined to
26 * use C++ type checking.
27 *
28 * Some config methods throw instances of the BSConfigExcpt
29 * class def'd in bs_config.h, which you should handle.
30 *
31 * These are the classes implemented here:
32 *
33 * -- BSCfgSysManip:
34 * a "manipulator" object of this class holds information
35 * for a CONFIG.SYS change, which is passed to BSConfigSys::Manipulate.
36 * See BSCfgSysManip::BSCfgSysManip for a description.
37 *
38 * -- BSConfigSys:
39 * the actual class which holds the CONFIG.SYS text file
40 * and allows changes to be made.
41 * This class does not have a corresponding "Undo" class.
42 * Instead, use BSCfgSysManip::AddToUndoList.
43 *
44 * -- BSRegisterClass:
45 * this allows registering classes with the WPS.
46 * See BSRegisterClass::Register for an example usage.
47 *
48 * -- BSDeregisterClass:
49 * the "Undo" class to the previous.
50 *
51 * -- BSReplaceClass:
52 * this allows WPS classes to be replaced.
53 * See BSReplaceClass::Replace for an example usage.
54 *
55 * -- BSUnreplaceClass:
56 * the "Undo" class to the previous.
57 *
58 * -- BSCreateWPSObject:
59 * for creating a WPS object.
60 *
61 * -- BSDeleteWPSObject:
62 * the "Undo" class for the previous, to delete a WPS object again.
63 *
64 * See bs_config.h for the declarations of these classes.
65 *
66 *@@header "cppbase\bs_config.h"
67 *@@header "cppbase\bs_config_impl.h"
68 */
69
70/*
71 * This file Copyright (C) 1999-2008 Ulrich M”ller.
72 * This program is free software; you can redistribute it and/or modify
73 * it under the terms of the GNU General Public License as published by
74 * the Free Software Foundation, in version 2 as it comes in the COPYING
75 * file of this distribution.
76 * This program is distributed in the hope that it will be useful,
77 * but WITHOUT ANY WARRANTY; without even the implied warranty of
78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79 * GNU General Public License for more details.
80 */
81
82#define OS2EMX_PLAIN_CHAR
83 // this is needed for "os2emx.h"; if this is defined,
84 // emx will define PSZ as _signed_ char, otherwise
85 // as unsigned char
86
87#define INCL_DOSSESMGR
88#define INCL_DOSSEMAPHORES
89#define INCL_DOSERRORS
90#define INCL_WINWINDOWMGR
91#define INCL_WINMESSAGEMGR
92#define INCL_WINDIALOGS
93#define INCL_WINSTDCNR
94#define INCL_WININPUT
95#define INCL_WINSYS
96#define INCL_WINSHELLDATA
97#define INCL_WINWORKPLACE
98#include <os2.h>
99
100#include <stdio.h>
101#include <stdlib.h>
102#include <string.h>
103#include <stdarg.h>
104
105#include "setup.h"
106
107// include's from helpers
108#include "helpers\dosh.h"
109#include "helpers\winh.h"
110#include "helpers\prfh.h"
111#include "helpers\stringh.h"
112#include "helpers\xstring.h"
113
114#include "helpers\configsys.h"
115
116// front-end includes
117#include "cppbase\bs_base.h"
118#include "cppbase\bs_list.h"
119#include "cppbase\bs_string.h"
120#include "cppbase\bs_errors.h"
121
122#include "cppbase\bs_logger.h"
123#include "cppbase\bs_config.h"
124#include "cppbase\bs_config_impl.h"
125
126#pragma hdrstop
127
128DEFINE_CLASS(BSConfigBase, BSRoot);
129
130DEFINE_CLASS(BSCfgSysManip, BSConfigBase);
131DEFINE_CLASS(BSConfigSys, BSRoot);
132DEFINE_CLASS(BSRegisterClass, BSConfigBase);
133DEFINE_CLASS(BSDeregisterClass, BSConfigBase);
134DEFINE_CLASS(BSReplaceClassBase, BSConfigBase);
135 DEFINE_CLASS(BSReplaceClass, BSReplaceClassBase);
136 DEFINE_CLASS(BSUnreplaceClass, BSReplaceClassBase);
137DEFINE_CLASS(BSCreateWPSObject, BSConfigBase);
138DEFINE_CLASS(BSDeleteWPSObject, BSConfigBase);
139DEFINE_CLASS(BSProfileBase, BSConfigBase);
140 DEFINE_CLASS(BSClearProfile, BSProfileBase);
141 DEFINE_CLASS(BSWriteProfile, BSProfileBase);
142DEFINE_CLASS(BSExecute, BSConfigBase);
143 DEFINE_CLASS(BSDeExecute, BSExecute);
144DEFINE_CLASS(BSKillProcess, BSConfigBase);
145
146 #define CONVERT(c, s) string str ## s(c, _ustr ## s); \
147 PCSZ pcsz ## s = str ## s.c_str()
148
149/* ******************************************************************
150 *
151 * BSCfgSysManip class
152 *
153 ********************************************************************/
154
155/*
156 *@@ BSCfgSysManip(char* pszConfigSys):
157 * this constructor translates a CONFIGSYS attribute (as used
158 * in the PCK tag and stored in the database) into a CONFIGSYSITEM
159 * structure.
160 *
161 * The BSCfgSysManip class is designed for use with the
162 * BSConfigSys class and describes manipulations to be done upon
163 * the CONFIG.SYS file (represented by the BSConfigSys class).
164 *
165 * Manipulating CONFIG.SYS works just as follows:
166 *
167 * 1) Create an instance of BSConfigSys:
168 *
169 + BSConfigSys *pConfigSys = new BSConfigSys;
170 *
171 * This will load your CONFIG.SYS file into the instance's memory.
172 *
173 * 2) Create an instance of BSCfgSysManip and specify the manipulation
174 * in the constructor:
175 *
176 + BSCfgSysManip *pManip = new BSCfgSysManip("SET TEST=YES | UNIQUE");
177 *
178 * The BSCfgSysManip class has a single constructor which takes a PSZ
179 * (char*) as input. This input string has exactly the format like
180 * with the CONFIGSYS attribute to the PCK tag in WarpIN installation
181 * scripts, like this (see the WarpIN Programmer's Reference for details):
182 *
183 + statement [| modifiers]
184 *
185 * "modifiers" can be one of the following:
186 + [UNIQUE[(xxx)]] [vertical]
187 + ADDRIGHT [vertical]
188 + ADDLEFT [vertical]
189 + REMOVELINE
190 + REMOVEPART
191 * with "xxx" being a search string.
192 *
193 * "vertical" can be one of the following:
194 + ADDTOP
195 + ADDAFTER(xxx)
196 + ADDBEFORE(xxx)
197 * with "xxx" being a search string.
198 *
199 * Examples:
200 + "BASEDEV=NEWDRIVR.SYS /WHATEVER | UNIQUE ADDAFTER(IBM1S506.ADD)"
201 + "SET PATH=C:\BLAH | ADDRIGHT"
202 *
203 * After this constructor has successfully converted pszConfigSys,
204 * all the instance data is valid (see cfgsys.h).
205 *
206 * However, this does _not_ handle macro resultion like in WarpIn
207 * scripts (which is done in warpin.cpp before calling the Manipulate
208 * method), because in this file scope we know nothing about the
209 * PackageInfo instances.
210 *
211 * 3) Create a CfgSysDone logger instance:
212 + BSCfgSysDoneLogger logger;
213 *
214 * 4) Invoke the BSConfigSys::Manipulate method with the BSCfgSysManip
215 * instance (this will add data to the logger):
216 + pConfigSys->Manipulate(logger, pManip);
217 *
218 * 5) Write CONFIG.SYS back to disk and clean up.
219 + pConfigSys->Flush(TRUE);
220 + delete pBSCfgSysManip;
221 + delete pConfigSys;
222 *
223 * Now, if you want to undo the changes later, call the static
224 * BSCfgSysManip::AddToUndoList method with the logger passed to
225 * to the various constructor calls (above), which will create
226 * a list of BSCfgSysManip instance which will be able to undo
227 * the changes again:
228 *
229 + list<BSCfgSysManip*> UndoList;
230 + BSCfgSysManip::AddToUndoList(UndoList, logger);
231 *
232 * and iterate over the list and call BSConfigSys::Manipulate with
233 * the objects on that list to undo the changes.
234 *
235 * Throws:
236 * -- BSConfigExcpt.
237 *
238 *@@changed V0.9.1 (2000-01-06) [umoeller]: added UNIQUE(xxx) support
239 *@@changed V0.9.5 (2000-08-26) [umoeller]: fixed UNIQUE(xxx) and REMOVELINE, which deleted wrong lines
240 */
241
242BSCfgSysManip::BSCfgSysManip(const ustring &ustrConfigSys)
243 : BSConfigBase(CFGT_CFGSYS, tBSCfgSysManip)
244{
245 PCSZ pcszConfigSys;
246
247 if (!(pcszConfigSys = ustrConfigSys.GetBuffer()))
248 throw BSConfigExcpt(CFGEXCPT_SYNTAX, 0);
249
250 // initialize all fields to zero
251 // memset(&_ConfigManip, 0, sizeof(_ConfigManip));
252 // V0.9.12 (2001-05-22) [umoeller]
253
254 _iReplaceMode = CFGRPL_ADD; // V1.0.4 (2004-12-18) [pr]
255 _iVertical = CFGVRT_BOTTOM;
256 // Moved above statements here from the else{} block below. If there wasn't a modifier,
257 // this was uninitialised garbage and CONFIG.SYS never got modified.
258
259 // now check if we have modifiers
260 PSZ pSep;
261 if (!(pSep = strchr(pcszConfigSys, '|')))
262 // no modifiers: just copy
263 _ustrNewLine = ustrConfigSys;
264 else
265 {
266 // we do have modifiers:
267 BOOL fVerticalsAllowed = TRUE;
268
269 // get rid of spaces before '|'
270 PSZ pSep2 = pSep-1;
271 while (*pSep2 == ' ')
272 pSep2--;
273
274 // get the "statement" part
275 _ustrNewLine.assignUtf8(pcszConfigSys, pSep2 + 1);
276
277 // remember the modifiers position
278 PSZ pModifiers = pSep + 1;
279 BOOL fReplaceModeFound = FALSE;
280 // now check for the replace mode;
281 // the default is 0 (CFGRPL_ADD)
282 fVerticalsAllowed = TRUE;
283
284 PSZ pszUnique;
285 if ((pszUnique = strhistr(pModifiers, "UNIQUE")))
286 {
287 _iReplaceMode = CFGRPL_UNIQUE;
288 fVerticalsAllowed = TRUE;
289 fReplaceModeFound = TRUE; // block future replacement modifiers
290
291 // check if we have a "UNIQUE(xxx)" syntax
292 PSZ psz;
293 if (psz = strhExtract(pszUnique, '(', ')', NULL))
294 {
295 // if found, this extracts the stuff between ( and );
296 // if not, this returns NULL
297 _ustrUniqueSearchString2.assignUtf8(psz);
298 free(psz);
299 }
300 }
301 if (strhistr(pModifiers, "ADDRIGHT"))
302 {
303 if (!fReplaceModeFound)
304 {
305 _iReplaceMode = CFGRPL_ADDRIGHT;
306 fVerticalsAllowed = TRUE;
307 fReplaceModeFound = TRUE; // block future replacement modifiers
308 }
309 else
310 {
311 // double replace mode found:
312 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
313 ustrConfigSys);
314 }
315 }
316 if (strhistr(pModifiers, "ADDLEFT"))
317 {
318 if (!fReplaceModeFound)
319 {
320 _iReplaceMode = CFGRPL_ADDLEFT;
321 fVerticalsAllowed = TRUE;
322 fReplaceModeFound = TRUE; // block future replacement modifiers
323 }
324 else
325 // double replace mode found:
326 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
327 ustrConfigSys);
328 }
329 if (strhistr(pModifiers, "REMOVELINE"))
330 {
331 if (!fReplaceModeFound)
332 {
333 _iReplaceMode = CFGRPL_REMOVELINE;
334 fVerticalsAllowed = FALSE;
335 fReplaceModeFound = TRUE; // block future replacement modifiers
336
337 // check also for stuff after "="
338 PSZ p;
339 if (p = strchr(_ustrNewLine.GetBuffer(), '='))
340 _ustrUniqueSearchString2.assignUtf8(p + 1);
341 }
342 else
343 // double replace mode found:
344 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
345 ustrConfigSys);
346 }
347 if (strhistr(pModifiers, "REMOVEPART"))
348 {
349 if (!fReplaceModeFound)
350 {
351 _iReplaceMode = CFGRPL_REMOVEPART;
352 fVerticalsAllowed = FALSE;
353 fReplaceModeFound = TRUE;
354 }
355 else
356 // double replace mode found:
357 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
358 ustrConfigSys);
359 }
360
361 // now parse vertical modifiers
362 BOOL fVerticalFound = FALSE;
363 if (strhistr(pModifiers, "ADDTOP"))
364 {
365 _iVertical = CFGVRT_TOP;
366 fVerticalFound = TRUE;
367 }
368 PSZ p2;
369 if ((p2 = strhistr(pModifiers, "ADDAFTER(")))
370 {
371 if (!fVerticalFound)
372 {
373 PSZ pEndOfSearch;
374 if (!(pEndOfSearch = strchr(p2, ')')))
375 {
376 ustring ustr;
377 ustr.assignUtf8(p2);
378 throw BSConfigExcpt(CFGEXCPT_INVALIDSEARCH, ustr);
379 }
380
381 _ustrVerticalSearchString.assignUtf8(
382 p2 + 9, // strlen("ADDAFTER(")
383 pEndOfSearch); // excluding that char
384
385 _iVertical = CFGVRT_AFTER;
386 fVerticalFound = TRUE;
387 }
388 else
389 {
390 ustring ustr;
391 ustr.assignUtf8(p2);
392 throw BSConfigExcpt(CFGEXCPT_INVALIDVERTICAL, ustr);
393 }
394 }
395 if ((p2 = strhistr(pModifiers, "ADDBEFORE(")))
396 {
397 if (!fVerticalFound)
398 {
399 PSZ pEndOfSearch;
400 if (!(pEndOfSearch = strchr(p2, ')')))
401 {
402 ustring ustr;
403 ustr.assignUtf8(p2);
404 throw BSConfigExcpt(CFGEXCPT_INVALIDSEARCH, ustr);
405 }
406
407 _ustrVerticalSearchString.assignUtf8(p2 + 10, // strlen("ADDBEFORE(")
408 pEndOfSearch); // excluding that char
409
410 _iVertical = CFGVRT_BEFORE;
411 fVerticalFound = TRUE;
412 }
413 else
414 {
415 ustring ustr;
416 ustr.assignUtf8(p2);
417 throw BSConfigExcpt(CFGEXCPT_INVALIDVERTICAL, ustr);
418 }
419 }
420
421 // finally check if vertical modifier is allowed at all
422 if ( (fVerticalFound) && (!fVerticalsAllowed) )
423 throw BSConfigExcpt(CFGEXCPT_INVALIDVERTICAL, ustrConfigSys);
424
425 } // end elseif (!pSep)
426}
427
428/*
429 *@@ DescribeType:
430 * describes the current manipulator type to the GUI.
431 *
432 *@@added V0.9.2 (2000-02-19) [umoeller]
433 */
434
435const char* BSCfgSysManip::DescribeType()
436{
437 return ("CONFIG.SYS manipulation");
438}
439
440/*
441 *@@ DescribeData:
442 * describes the current manipulator data to the GUI.
443 *
444 *@@added V0.9.2 (2000-02-19) [umoeller]
445 *@@changed V0.9.5 (2000-08-26) [umoeller]: UNIQUE wasn't reported right
446 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
447 */
448
449ustring BSCfgSysManip::DescribeData()
450{
451 ustring str;
452 BOOL fAddSpace = TRUE;
453
454 switch (_iReplaceMode)
455 {
456 case CFGRPL_UNIQUE:
457 str.appendUtf8("UNIQUE");
458 if (_ustrUniqueSearchString2())
459 {
460 str.appendUtf8("(");
461 str.append(_ustrUniqueSearchString2);
462 str.appendUtf8(")");
463 }
464 break;
465
466 case CFGRPL_ADDLEFT: str.appendUtf8("ADDLEFT"); break;
467 case CFGRPL_ADDRIGHT: str.appendUtf8("ADDRIGHT"); break;
468 case CFGRPL_REMOVELINE: str.appendUtf8("REMOVELINE"); break;
469 case CFGRPL_REMOVEPART: str.appendUtf8("REMOVEPART"); break;
470
471 default:
472 fAddSpace = FALSE;
473 break;
474 }
475
476 if (fAddSpace)
477 str.appendUtf8(" ");
478
479 switch (_iVertical)
480 {
481 case CFGVRT_TOP: str.appendUtf8("ADDTOP "); break;
482
483 case CFGVRT_BEFORE:
484 str.appendUtf8("BEFORE(");
485 str.append(_ustrVerticalSearchString);
486 str.appendUtf8(") ");
487 break;
488
489 case CFGVRT_AFTER:
490 str.appendUtf8("AFTER ");
491 str.append(_ustrVerticalSearchString);
492 str.appendUtf8(") ");
493 break;
494 }
495
496 str.append(_ustrNewLine);
497
498 return (str);
499}
500
501/*
502 *@@ AddToUndoList:
503 * static helper method to create BSCfgSysManip
504 * instances from the logger instance that was
505 * previously used with BSConfigSys::Manipulate.
506 *
507 * The new BSCfgSysManip objects are appended to
508 * the specified list and are exact opposites
509 * to the BSCfgSysManip objects that were stored
510 * in the logger. That is, if the logger registered
511 * that something was added to CONFIG.SYS, we
512 * create an object which removes that text again,
513 * and vice versa.
514 *
515 * Use this method to undo CONFIG.SYS changes
516 * and pass the objects on the list to BSConfigSys::Manipulate,
517 * since there is no corresponding "undo" class
518 * for BSConfigSys.
519 *
520 * See BSCfgSysManip::BSCfgSysManip for an example usage.
521 *
522 * This returns the number of items created.
523 *
524 * Throws:
525 * -- BSConfigExcpt.
526 */
527
528int BSCfgSysManip::AddToUndoList(list<BSConfigBase*> &List,
529 BSCfgSysDoneLogger &logger)
530{
531 // the logger in this case has a list of special PSZs,
532 // where the first three characters of each entry
533 // signify to us what was changed in CONFIG.SYS
534
535 PSZ pszLogStart = logger._pabLogString,
536 pszLogThis = pszLogStart;
537 int iCount = 0;
538
539 while (pszLogThis < pszLogStart + logger._cbLogString)
540 {
541 ULONG cbLogThis = strlen(pszLogThis);
542 string strNewModifiers;
543
544 // now check what we have in the log; the
545 // first three characters (followed by a
546 // space) signify what happened:
547 // -- "DLL": deleted line
548 // -- "DLP": deleted part of line
549 // -- "NWL": added an all new line
550 // -- "NWP": added a new part to an existing line
551
552 if (memicmp(pszLogThis, "DLL ", 4) == 0)
553 {
554 // line was deleted: re-insert that line (UNIQUE mode)
555 // strNewModifiers = "UNIQUE";
556 }
557 else if (memicmp(pszLogThis, "DLP ", 4) == 0)
558 {
559 // part of line was deleted: re-insert that line (ADDRIGHT mode)
560 strNewModifiers = "ADDRIGHT";
561 }
562 else if (memicmp(pszLogThis, "NWL ", 4) == 0)
563 {
564 // line was added: remove that whole line
565 strNewModifiers = "REMOVELINE";
566 // #### no, no, no!!! this removes an entire line...
567 }
568 else if (memicmp(pszLogThis, "NWP ", 4) == 0)
569 // part of line was added: remove that part
570 strNewModifiers = "REMOVEPART";
571 else
572 {
573 // none of the above: error
574 ustring ustr;
575 ustr.assignUtf8(pszLogThis);
576 throw BSConfigExcpt(CFGEXCPT_PARSELOG, ustr);
577 }
578
579 // something found: compose attribute string for manipulator
580 PSZ pszNewAttrs = (PSZ)malloc(strlen(pszLogThis)
581 + strNewModifiers.size()
582 + 30);
583 sprintf(pszNewAttrs, "%s | %s",
584 pszLogThis + 4, // stuff after "DLL " or whatever
585 strNewModifiers.c_str());
586
587 // add the undo manipulator to the _front_ of the
588 // list so that items are undone in reverse order
589 // (because if a line was replaced originally,
590 // we first have a "delete line" and then an
591 // "add line" entry in the log)
592 ustring ustr;
593 ustr.assignUtf8(pszNewAttrs);
594 List.push_front(new BSCfgSysManip(ustr));
595 free(pszNewAttrs);
596
597 pszLogThis += cbLogThis + 1; // go beyond null byte
598 iCount++;
599 }
600
601 return (iCount);
602}
603
604/* ******************************************************************
605 *
606 * BSConfigSys class
607 *
608 ********************************************************************/
609
610/*
611 *@@ BSConfigSys:
612 * the constructor, which loads the current CONFIG.SYS
613 * file from OS/2 boot drive into instance memory.
614 *
615 * Throws:
616 * -- BSConfigExcpt.
617 *
618 *@@changed V0.9.7 (2001-01-15) [umoeller]: now using csysLoadConfigSys
619 *@@changed WarpIN V1.0.9 (2006-02-16) [pr]: added _pszContentOld
620 */
621
622BSConfigSys::BSConfigSys() : BSRoot(tBSConfigSys)
623{
624 _pszContent = _pszContentOld = NULL;
625
626 /* sprintf(_szFilename, "%c:\\config.sys", doshQueryBootDrive());
627 // now read CONFIG.SYS file to initialize the dlg items
628 APIRET arc = doshLoadTextFile(_szFilename, &_pszContent); */
629
630 APIRET arc = csysLoadConfigSys(NULL, // default CONFIG.SYS
631 &_pszContent);
632
633 if (arc != NO_ERROR)
634 throw BSConfigExcpt(CFGEXCPT_OPEN, arc);
635 else
636 _pszContentOld = strhdup(_pszContent, NULL);
637
638 _fDirty = FALSE;
639}
640
641/*
642 *@@ ~ConfigSys:
643 * the destructor.
644 *
645 * This does _not_ write the file. Use BSConfigSys::Flush()
646 * before deleting an instance of this.
647 *
648 *@@changed WarpIN V1.0.9 (2006-02-16) [pr]: added _pszContentOld
649 */
650
651BSConfigSys::~BSConfigSys()
652{
653 if (_pszContent)
654 free(_pszContent);
655
656 if (_pszContentOld)
657 free(_pszContentOld);
658}
659
660/*
661 *@@ Manipulate:
662 * this monster method changes the data in our memory copy of
663 * CONFIG.SYS according to the BSCfgSysManip object, which you must
664 * have created before. See BSCfgSysManip::BSCfgSysManip for a
665 * description of this usage.
666 *
667 * This also takes a BSCfgSysDoneLogger as input where all the
668 * changes made to the CONFIG.SYS memory copy are logged. This
669 * logger can then be passed to BSConfigSys::Undo to have the
670 * changes undone again.
671 *
672 * Call BSConfigSys::Flush to have CONFIG.SYS written back to disk.
673 *
674 * Returns NO_ERROR if everything was OK or an error code.
675 *
676 *@@changed V0.9.18 (2002-03-08) [umoeller]: adjusted for Unicode; added codec
677 */
678
679int BSConfigSys::Manipulate(BSUniCodec &codecProcess, // in: codec for process codepage
680 BSCfgSysManip &Manip, // in: manipulator object
681 BSCfgSysDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
682 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
683{
684 int irc = 0;
685
686 XSTRING strLogger;
687 xstrInit(&strLogger, 0);
688
689 CONFIGMANIP cm;
690 memset(&cm, 0, sizeof(cm));
691
692 cm.iReplaceMode = Manip._iReplaceMode;
693
694 string strUniqueSearchString2(&codecProcess, Manip._ustrUniqueSearchString2);
695 cm.pszUniqueSearchString2 = strUniqueSearchString2.c_str();
696
697 cm.iVertical = Manip._iVertical;
698
699 string strVerticalSearchString(&codecProcess, Manip._ustrVerticalSearchString);
700 cm.pszVerticalSearchString = strVerticalSearchString.c_str();
701
702 string strNewLine(&codecProcess, Manip._ustrNewLine);
703 cm.pszNewLine = strNewLine.c_str();
704
705 irc = csysManipulate(&_pszContent,
706 &cm,
707 &_fDirty,
708 &strLogger);
709
710 // now parse the logger...
711 if (strLogger.ulLength)
712 {
713 // something to be logged:
714 PSZ p = strLogger.psz;
715
716 while (p)
717 {
718 PSZ pEOL;
719 if ( (pEOL = strhFindEOL(p, NULL))
720 && (*pEOL)
721 )
722 {
723 string strTemp(p, pEOL);
724
725 if (strTemp())
726 {
727 if (pLogFile)
728 // write to log file
729 pLogFile->Write("Updated CONFIG.SYS: \"%s\"",
730 strTemp.c_str());
731
732 if (pLogger)
733 {
734 // write to "done" logger:
735 ustring ustr(&codecProcess, strTemp);
736 pLogger->Append(ustr);
737 }
738 }
739 else
740 break;
741
742 p = pEOL + 1;
743 }
744 else
745 break;
746 }
747 }
748
749 xstrClear(&strLogger);
750
751 return (irc);
752}
753
754/*
755 *@@ Flush:
756 * this rewrites the CONFIG.SYS file on disk with the
757 * data we have in memory.
758 *
759 * This makes a backup copy in "CONFIG.003" style if
760 * (pszBackup != NULL). See doshCreateBackupFileName
761 * for details.
762 *
763 * Returns:
764 *
765 * -- 0: contents were dirty, written back to disk.
766 *
767 * -- 1: no error, but contents were clean, so no write-back
768 * was needed.
769 *
770 * Throws:
771 * -- BSConfigExcpt(CFGEXCPT_WRITE, APIRET).
772 *
773 *@@changed V0.9.3 (2000-05-03) [umoeller]: added more error checking
774 *@@changed V0.9.3 (2000-05-12) [umoeller]: added pszBackup
775 *@@changed V0.9.6 (2000-10-27) [umoeller]: added check if contents are dirty
776 *@@changed WarpIN V1.0.9 (2006-02-16) [pr]: added _pszContentOld
777 */
778
779int BSConfigSys::Flush(string *pstrBackup, // in/out: create backup?
780 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
781 const
782{
783 int irc = 0;
784
785 // WarpIN V1.0.9 (2006-02-16) [pr]: Check for content modification @@fixes 269
786 if ( _fDirty
787 && strhcmp (_pszContent, _pszContentOld)
788 )
789 {
790 PSZ pszBackup = NULL;
791 CHAR szBackup[CCHMAXPATH];
792 if (pstrBackup)
793 pszBackup = szBackup;
794
795 APIRET arc = csysWriteConfigSys(NULL, // default _szFilename,
796 _pszContent,
797 pszBackup); // create backup
798
799 if (arc)
800 {
801 if (pLogFile)
802 pLogFile->Write("Error %d occurred writing CONFIG.SYS back to disk",
803 arc);
804
805 throw BSConfigExcpt(CFGEXCPT_WRITE, arc);
806 }
807
808 if (pLogFile)
809 pLogFile->Write("CONFIG.SYS file written back to disk, backup is \"%s\"",
810 pszBackup);
811
812 if (pstrBackup)
813 pstrBackup->assign(szBackup);
814 }
815 else
816 irc = 1;
817
818 return (irc);
819}
820
821/* ******************************************************************
822 *
823 * BSRegisterClass class
824 *
825 ********************************************************************/
826
827/*
828 *@@ BSRegisterClass:
829 * this constructor translates a REGISTERCLASS attribute (as used
830 * in the PCK tag and stored in the database) into the BSRegisterClass
831 * instance data.
832 *
833 * Syntax:
834 *
835 + REGISTERCLASS="classname|dllpath"
836 *
837 * Throws:
838 * -- BSConfigExcpt.
839 */
840
841BSRegisterClass::BSRegisterClass(const ustring &ustrRegisterClass)
842 : BSConfigBase(CFGT_REGISTERCLASS, tBSRegisterClass)
843{
844 // find separator
845 PCSZ pcszRegisterClass = ustrRegisterClass.GetBuffer();
846 PCSZ pBegin;
847 if (!(pBegin = pcszRegisterClass))
848 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
849
850 PCSZ pEnd;
851 if (!(pEnd = strchr(pBegin, '|')))
852 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
853
854 // strip trailing spaces
855 PCSZ pEnd2 = pEnd;
856 while ((*pEnd2 == ' ') && (pEnd2 > pcszRegisterClass))
857 pEnd2--;
858
859 _ustrClassName.assignUtf8(pBegin, pEnd2);
860 if (!_ustrClassName())
861 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
862
863 pBegin = pEnd + 1;
864 // strip leading spaces
865 while ((*pBegin) && (*pBegin == ' '))
866 pBegin++;
867 _ustrModule.assignUtf8(pBegin);
868 if (!_ustrModule())
869 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
870}
871
872/*
873 *@@ DescribeType:
874 * describes the current manipulator type to the GUI.
875 *
876 *@@added V0.9.9 (2001-03-27) [umoeller]
877 */
878
879const char* BSRegisterClass::DescribeType()
880{
881 return ("WPS class registration");
882}
883
884/*
885 *@@ DescribeData:
886 * describes the current manipulator data to the GUI.
887 *
888 *@@added V0.9.9 (2001-03-27) [umoeller]
889 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
890 */
891
892ustring BSRegisterClass::DescribeData()
893{
894 ustring str = _ustrClassName;
895 str.appendUtf8(" in ");
896 str += _ustrModule;
897
898 return (str);
899}
900
901/*
902 *@@ IsRegistered:
903 * this returns TRUE if a class of the same WPS class name
904 * as this instance is already registered with the WPS.
905 * In that case, the module of the registered class is
906 * copied into strModule.
907 *
908 * This throws a BSConfigExcpt with REGEXCPT_QUERYCLASSLIST
909 * if the class list could not be queried.
910 *
911 *@@changed V0.9.18 (2002-03-08) [umoeller]: now using string for buffer, added codec
912 */
913
914bool BSRegisterClass::IsRegistered(BSUniCodec &codecProcess, // in: codec for process codepage
915 ustring &ustrModule)
916 const
917{
918 BOOL fInstalled = FALSE;
919 PBYTE pClassList,
920 pClassThis = 0;
921 if (pClassList = winhQueryWPSClassList())
922 {
923 string strClassName(&codecProcess, _ustrClassName);
924 if ((pClassThis = winhQueryWPSClass(pClassList, strClassName.c_str())))
925 {
926 fInstalled = TRUE;
927 ustrModule.assignCP(&codecProcess, ((POBJCLASS)pClassThis)->pszModName);
928 }
929
930 free(pClassList);
931 }
932 else
933 throw BSConfigExcpt(REGEXCPT_QUERYCLASSLIST, 0);
934
935 return (fInstalled);
936}
937
938/*
939 *@@ Register:
940 * this attempts to register the class.
941 *
942 * If (fReplace == TRUE), we do not call
943 * BSRegisterClass::IsRegistered before registering
944 * this, i.e. we will always register the class,
945 * even if it's already registered.
946 *
947 * If (fReplace == FALSE) and BSRegisterClass::IsRegistered
948 * returned TRUE, we throw a BSConfigExcpt with
949 * REGEXCPT_ALREADYREGISTERED and pszSubstr set to the
950 * file name of the registered DLL. Note that IsRegistered might
951 * in turn throw BSConfigExcpt with REGEXCPT_QUERYCLASSLIST.
952 *
953 * If registering the class failed, this throws a
954 * BSConfigExcpt with REGEXCPT_REGISTER and iData set
955 * to the APIRET of winhRegisterClass.
956 *
957 * This method can take a BSDoneLoggerBase object as input, which
958 * can later be used with the BSDeregisterClass::AddToUndoList
959 * static class method to easily create a list of BSDeregisterClass
960 * objects to undo the changes made.
961 *
962 * Example usage (exception handling omitted):
963 + BSRegisterDoneLogger logger;
964 + // create logger instance
965 + BSRegisterClass RegClass("XFolder|C:\XFOLDER\XFLDR.DLL");
966 + // create BSRegisterClass instance:
967 + RegClass.Register(TRUE, logger);
968 + ... // register more classes with the same logger
969 +
970 + // now create undo list
971 + list<BSDeregisterClass*> List;
972 + BSDeregisterClass::AddToUndoList(List, logger);
973 + list<BSDeregisterClass*>::iterator DeregStart = List.begin(),
974 + DeregEnd = List.end();
975 + for (; DeregStart != DeregEnd; DeregStart++)
976 + (**DeregStart).Deregister;
977 *
978 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
979 *@@changed V0.9.18 (2002-03-08) [umoeller]: added missing log file entry
980 */
981
982int BSRegisterClass::Register(BSUniCodec &codecProcess, // in: codec for process codepage
983 bool fReplace,
984 BSRegisterDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
985 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
986 const
987{
988 int irc = 0;
989
990 if (fReplace == FALSE)
991 {
992 ustring ustrModule;
993 if (IsRegistered(codecProcess, ustrModule))
994 throw BSConfigExcpt(REGEXCPT_ALREADYREGISTERED, ustrModule);
995 }
996
997 CONVERT(&codecProcess, ClassName);
998 CONVERT(&codecProcess, Module);
999
1000 CHAR szBuf[1000];
1001 APIRET arc = winhRegisterClass(pcszClassName,
1002 pcszModule,
1003 szBuf,
1004 sizeof(szBuf));
1005 // always record in logger, even if failed,
1006 // because the class is in the class list anyway
1007 if (pLogger)
1008 pLogger->Append(_ustrClassName);
1009
1010 if (arc != NO_ERROR)
1011 {
1012 // this was missing V0.9.18 (2002-03-08) [umoeller]
1013 if (pLogFile)
1014 pLogFile->Write("Error %d registering WPS class \"%s\"",
1015 arc,
1016 pcszClassName);
1017
1018 throw BSConfigExcpt(REGEXCPT_REGISTER, arc);
1019 }
1020
1021 // this was missing V0.9.18 (2002-03-08) [umoeller]
1022 if (pLogFile)
1023 pLogFile->Write("Registered WPS class \"%s\"",
1024 pcszClassName);
1025
1026 return (irc);
1027}
1028
1029/* ******************************************************************
1030 *
1031 * BSDeregisterClass class
1032 *
1033 ********************************************************************/
1034
1035/*
1036 *@@ BSDeregisterClass:
1037 * the constructor, which in this case takes a simple
1038 * PSZ class name as input.
1039 */
1040
1041BSDeregisterClass::BSDeregisterClass(const ustring &ustrDeregisterClass)
1042 : BSConfigBase(CFGT_DEREGISTERCLASS, tBSDeregisterClass)
1043{
1044 _ustrClassName = ustrDeregisterClass;
1045}
1046
1047/*
1048 *@@ DescribeType:
1049 * describes the current manipulator type to the GUI.
1050 *
1051 *@@added V0.9.2 (2000-02-19) [umoeller]
1052 */
1053
1054const char* BSDeregisterClass::DescribeType()
1055{
1056 return ("WPS class deregistration");
1057}
1058
1059/*
1060 *@@ DescribeData:
1061 * describes the current manipulator data to the GUI.
1062 *
1063 *@@added V0.9.2 (2000-02-19) [umoeller]
1064 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1065 */
1066
1067ustring BSDeregisterClass::DescribeData()
1068{
1069 return (_ustrClassName);
1070}
1071
1072/*
1073 *@@ Deregister:
1074 * this attempts to deregister the class.
1075 *
1076 * Throws:
1077 * -- BSConfigExcpt.
1078 *
1079 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1080 */
1081
1082int BSDeregisterClass::Deregister(BSUniCodec &codecProcess, // in: codec for process codepage
1083 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1084 const
1085{
1086 int irc = 0;
1087
1088 CONVERT(&codecProcess, ClassName); // creates local string strXXX, PCSZ pcszXXX
1089
1090 if (!WinDeregisterObjectClass(pcszClassName))
1091 {
1092 if (pLogFile)
1093 pLogFile->Write("An error occurred deregistering WPS class \"%s\"",
1094 pcszClassName);
1095
1096 throw BSConfigExcpt(REGEXCPT_DEREGISTER, _ustrClassName);
1097 }
1098
1099 if (pLogFile)
1100 pLogFile->Write("Deregistered WPS class \"%s\"",
1101 pcszClassName);
1102
1103 return (irc);
1104}
1105
1106/*
1107 *@@ AddToUndoList:
1108 * static helper method to create BSDeregisterClass
1109 * instances from the logger instance that was
1110 * previously used with BSRegisterClass::Register.
1111 *
1112 * The new BSDeregisterClass objects are appended to
1113 * the specified list.
1114 *
1115 * See BSRegisterClass::Register for an example usage.
1116 *
1117 * This returns the number of items created.
1118 */
1119
1120int BSDeregisterClass::AddToUndoList(list<BSConfigBase*> &List,
1121 BSRegisterDoneLogger &logger)
1122{
1123 // the logger in this case has a simple list of PSZs with all
1124 // the class names that were registered, each of which is terminated
1125 // with a null character
1126
1127 PSZ pszLogStart = logger._pabLogString,
1128 pszLogThis = pszLogStart;
1129 int iCount = 0;
1130
1131 while (pszLogThis < pszLogStart + logger._cbLogString)
1132 {
1133 ULONG cbLogThis = strlen(pszLogThis);
1134 ustring ustr;
1135 ustr.assignUtf8(pszLogThis);
1136 List.push_back(new BSDeregisterClass(ustr));
1137 pszLogThis += cbLogThis + 1; // go beyond null byte
1138 iCount++;
1139 }
1140
1141 return (iCount);
1142}
1143
1144/* ******************************************************************
1145 *
1146 * BSReplaceClass class
1147 *
1148 ********************************************************************/
1149
1150/*
1151 *@@ BSReplaceClassBase:
1152 * this constructor translates a REPLACECLASS attribute (as used
1153 * in the PCK tag and stored in the database) into the BSReplaceClass
1154 * instance data.
1155 *
1156 * Syntax:
1157 *
1158 + REPLACECLASS="oldclassname|newclassname"
1159 *
1160 *@@changed V0.9.19 (2002-05-07) [umoeller]: changed inheritance hierarchy here
1161 */
1162
1163BSReplaceClassBase::BSReplaceClassBase(const ustring &ustrReplaceClass,
1164 ULONG cfgt,
1165 BSClassID &Class)
1166 : BSConfigBase(cfgt, Class)
1167{
1168 PCSZ pcszReplaceClass = ustrReplaceClass.GetBuffer();
1169
1170 // find separator
1171 PCSZ pBegin;
1172 if (!(pBegin = pcszReplaceClass))
1173 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1174
1175 PCSZ pEnd;
1176 if (!(pEnd = strchr(pBegin, '|')))
1177 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1178
1179 // strip trailing spaces
1180 PCSZ pEnd2 = pEnd;
1181 while ((*pEnd2 == ' ') && (pEnd2 > pcszReplaceClass))
1182 pEnd2--;
1183
1184 _ustrOldClassName.assignUtf8(pBegin, pEnd2);
1185 if (!_ustrOldClassName())
1186 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1187
1188 pBegin = pEnd + 1;
1189 // strip leading spaces
1190 while ((*pBegin) && (*pBegin == ' '))
1191 pBegin++;
1192 _ustrNewClassName.assignUtf8(pBegin);
1193 if (!_ustrNewClassName())
1194 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1195}
1196
1197/*
1198 *@@ DescribeType:
1199 * describes the current manipulator type to the GUI.
1200 *
1201 *@@added V0.9.2 (2000-02-19) [umoeller]
1202 */
1203
1204const char* BSReplaceClass::DescribeType()
1205{
1206 return ("WPS class replacement");
1207}
1208
1209/*
1210 *@@ DescribeData:
1211 * describes the current manipulator data to the GUI.
1212 *
1213 *@@added V0.9.2 (2000-02-19) [umoeller]
1214 *@@changed V0.9.5 (2000-08-26) [umoeller]: UNIQUE wasn't reported right
1215 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1216 */
1217
1218ustring BSReplaceClass::DescribeData()
1219{
1220 ustring str = _ustrOldClassName;
1221 str.appendUtf8(" with ");
1222 str += _ustrNewClassName;
1223
1224 return (str);
1225}
1226
1227/*
1228 *@@ Replace:
1229 * this attempts to replace the class or undo
1230 * an existing replacement (if fReplace == FALSE).
1231 *
1232 * If replacing the class failed, this throws a
1233 * BSConfigExcpt with REGEXCPT_REPLACE.
1234 *
1235 * Example usage (exception handling omitted):
1236 + BSReplaceDoneLogger logger;
1237 + // create logger instance
1238 + BSReplaceClass ReplClass("WPFolder;XFolder");
1239 + // create BSReplaceClass instance:
1240 + ReplClass.Replace(TRUE, logger);
1241 + ... // replace more classes with the same logger
1242 +
1243 + // now create undo list
1244 + list<BSUnreplaceClass*> List;
1245 + BSUnreplaceClass::AddToUndoList(List, logger);
1246 + list<BSUnreplaceClass*>::iterator UnrplStart = List.begin(),
1247 + UnrplEnd = List.end();
1248 + for (; UnrplStart != UnrplEnd; UnrplStart++)
1249 + (**UnrplStart).Unreplace;
1250 *
1251 *@@changed V0.9.1 (2000-01-05) [umoeller]: finally added logging, which was missing
1252 *@@changed V0.9.9 (2001-03-30) [umoeller]: fixed wrong logging if replace failed
1253 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1254 */
1255
1256int BSReplaceClass::Replace(BSUniCodec &codecProcess, // in: codec for process codepage
1257 BSReplaceDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
1258 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1259 const
1260{
1261 int irc = 0;
1262
1263 CONVERT(&codecProcess, OldClassName);
1264 CONVERT(&codecProcess, NewClassName);
1265
1266 BOOL brc = WinReplaceObjectClass(pcszOldClassName,
1267 pcszNewClassName,
1268 TRUE); // replace
1269 // always record in logger, even if failed,
1270 // because the class is in the class list anyway
1271 // V0.9.9 (2001-03-30) [umoeller]
1272 if (pLogger)
1273 {
1274 ustring ustr2Append(_ustrOldClassName);
1275 ustr2Append.appendUtf8("|");
1276 ustr2Append += _ustrNewClassName;
1277 pLogger->Append(ustr2Append);
1278 }
1279
1280
1281 if (!brc)
1282 {
1283 if (pLogFile)
1284 pLogFile->Write("An error occurred replacing WPS class \"%s\" with \"%s\"",
1285 pcszOldClassName,
1286 pcszNewClassName);
1287
1288 throw BSConfigExcpt(REGEXCPT_REPLACE, 0);
1289 }
1290
1291 // success:
1292 if (pLogFile)
1293 pLogFile->Write("Replaced WPS class \"%s\" with \"%s\"",
1294 pcszOldClassName,
1295 pcszNewClassName);
1296
1297 return (irc);
1298}
1299
1300/* ******************************************************************
1301 *
1302 * BSUnreplaceClass class
1303 *
1304 ********************************************************************/
1305
1306/*
1307 *@@ DescribeType:
1308 * describes the current manipulator type to the GUI.
1309 *
1310 *@@added V0.9.2 (2000-02-19) [umoeller]
1311 */
1312
1313const char* BSUnreplaceClass::DescribeType()
1314{
1315 return ("WPS class un-replacement");
1316}
1317
1318/*
1319 *@@ DescribeData:
1320 * describes the current manipulator data to the GUI.
1321 *
1322 *@@added V0.9.2 (2000-02-19) [umoeller]
1323 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1324 */
1325
1326ustring BSUnreplaceClass::DescribeData()
1327{
1328 ustring ustr = _ustrOldClassName;
1329 ustr.appendUtf8(" with ");
1330 ustr += _ustrNewClassName;
1331
1332 return (ustr);
1333}
1334
1335/*
1336 *@@ Unreplace:
1337 * this attempts to unreplace the class.
1338 * Throws a BSConfigExcpt upon failure.
1339 *
1340 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1341 */
1342
1343int BSUnreplaceClass::Unreplace(BSUniCodec &codecProcess, // in: codec for process codepage,
1344 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1345 const
1346{
1347 int irc = 0;
1348
1349 CONVERT(&codecProcess, OldClassName);
1350 CONVERT(&codecProcess, NewClassName);
1351
1352 if (!WinReplaceObjectClass(pcszOldClassName,
1353 pcszNewClassName,
1354 FALSE))
1355 {
1356 if (pLogFile)
1357 pLogFile->Write("Error undoing WPS class replacement of \"%s\" with \"%s\"",
1358 pcszOldClassName,
1359 pcszNewClassName);
1360
1361 throw BSConfigExcpt(REGEXCPT_UNREPLACE, 0);
1362 }
1363
1364 // success:
1365 if (pLogFile)
1366 pLogFile->Write("Undid WPS class replacement of \"%s\" with \"%s\"",
1367 pcszOldClassName,
1368 pcszNewClassName);
1369
1370 return (irc);
1371}
1372
1373/*
1374 *@@ AddToUndoList:
1375 * static helper method to create BSUnreplaceClass
1376 * instances from the logger instance that was
1377 * previously used with BSRegisterClass::Register.
1378 *
1379 * The new BSUnreplaceClass objects are appended to
1380 * the specified list.
1381 *
1382 * See BSReplaceClass::Replace for an example usage.
1383 *
1384 * This returns the number of items created.
1385 */
1386
1387int BSUnreplaceClass::AddToUndoList(list<BSConfigBase*> &List,
1388 BSReplaceDoneLogger &logger)
1389{
1390 // the logger in this case has a simple list of PSZs with all
1391 // the class names that were registered, each of which is terminated
1392 // with a null character
1393
1394 PSZ pszLogStart = logger._pabLogString,
1395 pszLogThis = pszLogStart;
1396 int iCount = 0;
1397
1398 while (pszLogThis < pszLogStart + logger._cbLogString)
1399 {
1400 ULONG cbLogThis = strlen(pszLogThis);
1401 ustring ustr;
1402 ustr.assignUtf8(pszLogThis);
1403 List.push_back(new BSUnreplaceClass(ustr));
1404 // this calls the inherited BSReplaceClass
1405 // constructor, which will parse the thing
1406 pszLogThis += cbLogThis + 1; // go beyond null byte
1407 iCount++;
1408 }
1409
1410 return (iCount);
1411}
1412
1413/* ******************************************************************
1414 *
1415 * BSCreateWPSObject class
1416 *
1417 ********************************************************************/
1418
1419/*
1420 *@@ BSCreateWPSObject:
1421 * this constructor translates a CREATEOBJECT attribute (as used
1422 * in the PCK tag and stored in the database) into the BSCreateWPSObject
1423 * instance data.
1424 *
1425 * Syntax:
1426 *
1427 + CREATEOBJECT="[REPLACE] classname|title|location[|config]]"
1428 + CREATEOBJECT="[FAIL] classname|title|location[|config]]"
1429 *
1430 * Throws:
1431 * -- BSConfigExcpt.
1432 *
1433 *@@changed V0.9.3 (2000-04-08) [umoeller]: "REPLACE" wasn't evaluated; fixed. Thanks, Cornelis Bockemhl.
1434 *@@changed V0.9.15 (2001-08-26) [umoeller]: added WPOEXCPT_INVALIDLOCATION checks
1435 *@@changed V0.9.19 (2002-04-14) [umoeller]: REPLACE was never detected, fixed
1436 *@@changed V1.0.14 (2006-12-03) [pr]: added FAIL mode @@fixes 893
1437 */
1438
1439BSCreateWPSObject::BSCreateWPSObject(const ustring &ustrCreateObject)
1440 : BSConfigBase(CFGT_CREATEOBJECT, tBSCreateWPSObject)
1441{
1442 PCSZ pcszCreateObject = ustrCreateObject.GetBuffer();
1443
1444 // extract class name
1445 PCSZ pBegin;
1446 if (!(pBegin = pcszCreateObject))
1447 throw BSConfigExcpt(WPOEXCPT_NOCLASS, ustrCreateObject);
1448
1449 if (!memcmp(pBegin, "REPLACE ", 8))
1450 {
1451 _ulFlags = CO_REPLACEIFEXISTS; // V1.0.14 (2006-12-03) [pr]
1452 pBegin += 8;
1453 while (*pBegin == ' ')
1454 pBegin++;
1455 }
1456 else
1457 if (!memcmp(pBegin, "FAIL ", 5)) // V1.0.14 (2006-12-03) [pr]
1458 {
1459 _ulFlags = CO_FAILIFEXISTS;
1460 pBegin += 5;
1461 while (*pBegin == ' ')
1462 pBegin++;
1463 }
1464 else
1465 _ulFlags = CO_UPDATEIFEXISTS; // V1.0.14 (2006-12-03) [pr]
1466
1467 PSZ pEnd;
1468 if (pEnd = strchr(pBegin, '|'))
1469 {
1470 _ustrClassName.assignUtf8(pBegin, pEnd);
1471
1472 // extract title
1473 pBegin = pEnd + 1;
1474 if (pEnd = strchr(pBegin, '|'))
1475 {
1476 _ustrTitle.assignUtf8(pBegin, pEnd);
1477
1478 // extract location
1479 pBegin = pEnd + 1;
1480 if (pEnd = strchr(pBegin, '|'))
1481 {
1482 // yet another separator found: we then have a config parameter
1483 _ustrLocation.assignUtf8(pBegin, pEnd);
1484
1485 // extract config (rest of pszCreateObject)
1486 pBegin = pEnd + 1;
1487 _ustrSetupString.assignUtf8(pBegin);
1488 }
1489 else
1490 // no separator after "location" found:
1491 // duplicate whole string
1492 _ustrLocation.assignUtf8(pBegin);
1493
1494 if (!_ustrLocation())
1495 throw BSConfigExcpt(WPOEXCPT_NOLOCATION, ustrCreateObject);
1496
1497 // check if the location is correctly in <> brackets
1498 // V0.9.15 (2001-08-26) [umoeller]
1499 PCSZ pcszLocation = _ustrLocation.GetBuffer();
1500 if ( (pcszLocation[0] == '<')
1501 && (pcszLocation[_ustrLocation.length() - 1] != '>')
1502 )
1503 throw BSConfigExcpt(WPOEXCPT_INVALIDLOCATIONSTRING, ustrCreateObject);
1504 }
1505 else
1506 throw BSConfigExcpt(WPOEXCPT_NOTITLE, ustrCreateObject);
1507 }
1508 else
1509 throw BSConfigExcpt(WPOEXCPT_NOCLASS, ustrCreateObject);
1510}
1511
1512/*
1513 *@@ DescribeType:
1514 * describes the current manipulator type to the GUI.
1515 *
1516 *@@added V0.9.9 (2001-03-27) [umoeller]
1517 */
1518
1519const char* BSCreateWPSObject::DescribeType()
1520{
1521 return ("WPS object");
1522}
1523
1524/*
1525 *@@ DescribeData:
1526 * describes the current manipulator data to the GUI.
1527 *
1528 *@@added V0.9.9 (2001-03-27) [umoeller]
1529 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1530 */
1531
1532ustring BSCreateWPSObject::DescribeData()
1533{
1534 ustring ustr = _ustrClassName;
1535 ustr.appendUtf8(" ");
1536 ustr += _ustrTitle;
1537 ustr.appendUtf8(" ");
1538 ustr += _ustrLocation;
1539 ustr.appendUtf8(" ");
1540 ustr += _ustrSetupString;
1541
1542 return (ustr);
1543}
1544
1545/*
1546 *@@ CreateObject:
1547 * this attempts to create the WPS object
1548 * with the instance data.
1549 *
1550 * Throws a BSConfigExcpt with WPOEXCPT_CREATE
1551 * if this fails.
1552 *
1553 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1554 *@@changed V1.0.14 (2006-12-03) [pr]: added FAIL mode @@fixes 893
1555 */
1556
1557void BSCreateWPSObject::CreateObject(BSUniCodec &codecProcess, // in: codec for process codepage,
1558 BSWPSObjectsDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
1559 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1560{
1561 CONVERT(&codecProcess, ClassName); // creates local string strXXX, PCSZ pcszXXX
1562 CONVERT(&codecProcess, Title); // creates local string strXXX, PCSZ pcszXXX
1563 CONVERT(&codecProcess, SetupString); // creates local string strXXX, PCSZ pcszXXX
1564 CONVERT(&codecProcess, Location); // creates local string strXXX, PCSZ pcszXXX
1565
1566 // check if the target folder exists, this is the most common problem
1567 // if WinCreateObject fails
1568 // V0.9.19 (2002-06-15) [umoeller]
1569
1570 if (!WinQueryObject(pcszLocation))
1571 {
1572 if (pLogFile)
1573 pLogFile->Write("Error creating WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\": Invalid target folder",
1574 pcszTitle,
1575 pcszClassName,
1576 pcszLocation,
1577 pcszSetupString);
1578
1579 throw BSConfigExcpt(WPOEXCPT_CREATE_BADLOCATION, _ustrTitle);
1580 }
1581
1582 if (!(_hobj = WinCreateObject(pcszClassName,
1583 pcszTitle,
1584 pcszSetupString,
1585 pcszLocation,
1586 _ulFlags)))
1587 {
1588 if (_ulFlags == CO_FAILIFEXISTS) // V1.0.14 (2006-12-03) [pr]
1589 {
1590 if (pLogFile)
1591 pLogFile->Write("WPS object already exists \"%s\", class \"%s\", location \"%s\", setup \"%s\"",
1592 pcszTitle,
1593 pcszClassName,
1594 pcszLocation,
1595 pcszSetupString);
1596 }
1597 else
1598 {
1599 if (pLogFile)
1600 pLogFile->Write("Error creating WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\"",
1601 pcszTitle,
1602 pcszClassName,
1603 pcszLocation,
1604 pcszSetupString);
1605
1606 throw BSConfigExcpt(WPOEXCPT_CREATE, _ustrTitle);
1607 }
1608 }
1609 else
1610 {
1611 // V1.0.5 (2005-02-17) [pr]
1612 // We now save the object synchronously to prevent objects getting lost if we
1613 // restart the WPS imminently due to a class registration for example. @@fixes 634.
1614 WinSaveObject (_hobj, FALSE);
1615 if (pLogFile)
1616 {
1617 pLogFile->Write("Created WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\"",
1618 pcszTitle,
1619 pcszClassName,
1620 pcszLocation,
1621 pcszSetupString);
1622 pLogFile->Write("HOBJECT is 0x%lX", _hobj);
1623 }
1624 }
1625
1626 // store the object ID in the logger
1627 PCSZ pObjectID;
1628 if ( // do we have a setup string at all?
1629 (pObjectID = _ustrSetupString.GetBuffer())
1630 // does it contain an object ID?
1631 && (pObjectID = strhistr(pObjectID,
1632 "OBJECTID=<"))
1633 )
1634 {
1635 PCSZ pBegin = pObjectID + 9; // points to '<' now
1636 PCSZ pEnd;
1637 if (pEnd = strchr(pBegin, '>'))
1638 {
1639 ustring ustrObjectID;
1640 ustrObjectID.assignUtf8(pBegin, pEnd + 1);
1641 if (pLogger)
1642 pLogger->Append(ustrObjectID);
1643 }
1644 }
1645}
1646
1647/* ******************************************************************
1648 *
1649 * BSDeleteWPSObject class
1650 *
1651 ********************************************************************/
1652
1653/*
1654 *@@ BSDeleteWPSObject:
1655 * the constructor, which in this case takes a simple
1656 * PSZ object ID as input.
1657 */
1658
1659BSDeleteWPSObject::BSDeleteWPSObject(const ustring &ustrID2Delete)
1660 : BSConfigBase(CFGT_DELETEOBJECT, tBSDeleteWPSObject)
1661{
1662 _ustrObjectID = ustrID2Delete;
1663}
1664
1665/*
1666 *@@ DescribeType:
1667 * describes the current manipulator type to the GUI.
1668 *
1669 *@@added V0.9.2 (2000-02-19) [umoeller]
1670 */
1671
1672const char* BSDeleteWPSObject::DescribeType()
1673{
1674 return ("WPS object deletion");
1675}
1676
1677/*
1678 *@@ DescribeData:
1679 * describes the current manipulator data to the GUI.
1680 *
1681 *@@added V0.9.2 (2000-02-19) [umoeller]
1682 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1683 */
1684
1685ustring BSDeleteWPSObject::DescribeData()
1686{
1687 return (_ustrObjectID);
1688}
1689
1690/*
1691 *@@ Delete:
1692 * this attempts to delete the object.
1693 * Throws a BSConfigExcpt upon failure.
1694 *
1695 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1696 *@@changed V1.0.18 (2008-09-27) [pr]: no error if object no longer exists @@fixes 1062
1697 */
1698
1699int BSDeleteWPSObject::Delete(BSUniCodec &codecProcess,
1700 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1701 const
1702{
1703 int irc = 0;
1704
1705 CONVERT(&codecProcess, ObjectID); // creates local string strXXX, PCSZ pcszXXX
1706
1707 HOBJECT hobj;
1708 if (!(hobj = WinQueryObject(pcszObjectID)))
1709 {
1710 if (pLogFile)
1711 pLogFile->Write("Error locating WPS object \"%s\"",
1712 pcszObjectID);
1713 }
1714 else
1715 if (!WinDestroyObject(hobj))
1716 {
1717 if (pLogFile)
1718 pLogFile->Write("Error deleting WPS object \"%s\", HOBJECT was 0x%lX",
1719 pcszObjectID,
1720 hobj);
1721
1722 throw BSConfigExcpt(WPOEXCPT_DELETEOBJECT, 0);
1723 }
1724
1725 return (irc);
1726}
1727
1728/*
1729 *@@ AddToUndoList:
1730 * static helper method to create BSDeleteWPSObject
1731 * instances from the logger instance that was
1732 * previously used with BSRegisterClass::Register.
1733 *
1734 * The new BSDeleteWPSObject objects are appended to
1735 * the specified list.
1736 *
1737 * This returns the number of items created.
1738 */
1739
1740int BSDeleteWPSObject::AddToUndoList(list<BSConfigBase*> &List,
1741 BSWPSObjectsDoneLogger &logger)
1742{
1743 // the logger in this case has a simple list of PSZs with all
1744 // the object IDs that were created, each of which is terminated
1745 // with a null character
1746
1747 PSZ pszLogStart = logger._pabLogString,
1748 pszLogThis = pszLogStart;
1749 int iCount = 0;
1750
1751 while (pszLogThis < pszLogStart + logger._cbLogString)
1752 {
1753 ULONG cbLogThis = strlen(pszLogThis);
1754 ustring ustr;
1755 ustr.assignUtf8(pszLogThis);
1756 List.push_back(new BSDeleteWPSObject(ustr));
1757 pszLogThis += cbLogThis + 1; // go beyond null byte
1758 iCount++;
1759 }
1760
1761 return (iCount);
1762}
1763
1764/* ******************************************************************
1765 *
1766 * BSClearProfile class
1767 *
1768 ********************************************************************/
1769
1770/*
1771 *@@ DescribeType:
1772 * describes the current manipulator type to the GUI.
1773 *
1774 *@@added V0.9.2 (2000-02-19) [umoeller]
1775 */
1776
1777const char* BSProfileBase::DescribeType()
1778{
1779 return ("Profile data");
1780}
1781
1782/*
1783 *@@ DescribeData:
1784 * describes the current manipulator data to the GUI.
1785 *
1786 *@@added V0.9.2 (2000-02-19) [umoeller]
1787 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1788 */
1789
1790ustring BSProfileBase::DescribeData()
1791{
1792 return (DescribePrfKey());
1793}
1794
1795/*
1796 *@@ DescribePrfKey:
1797 * returns a descriptive string describing the
1798 * member fields, a la "USER\app\key".
1799 *
1800 *@@added V0.9.1 (2000-02-12) [umoeller]
1801 */
1802
1803ustring BSProfileBase::DescribePrfKey() const
1804{
1805 ustring str(_ustrProfile);
1806 if (_ustrApplication())
1807 {
1808 str.appendUtf8("\\");
1809 str += _ustrApplication;
1810
1811 if (_ustrKey())
1812 {
1813 str.appendUtf8("\\");
1814 str += _ustrKey;
1815 }
1816 }
1817
1818 return (str);
1819}
1820
1821/*
1822 *@@ DescribePrfKey:
1823 *
1824 *@@added V0.9.18 (2002-03-08) [umoeller]
1825 */
1826
1827string BSProfileBase::DescribePrfKey(BSUniCodec &codecProcess) const
1828{
1829 string str(&codecProcess, DescribePrfKey());
1830 return str;
1831}
1832
1833/*
1834 *@@ BSClearProfile:
1835 *
1836 * Syntax:
1837 *
1838 + CLEARPROFILE="profile\application[\key]"
1839 *
1840 *@@added V0.9.1 (2000-02-07) [umoeller]
1841 *@@changed V1.0.5 (2005-03-06) [pr]: Improved parsing of profiles with path names. @@fixes 633
1842 */
1843
1844BSClearProfile::BSClearProfile(const ustring &ustrClearProfile)
1845 : BSProfileBase(CFGT_CLEARPROFILE, tBSClearProfile)
1846{
1847 PCSZ pcszClearProfile = ustrClearProfile.GetBuffer();
1848
1849 // get profile
1850 PCSZ pFirstBackslash;
1851 if (pFirstBackslash = strchr(pcszClearProfile, '\\'))
1852 {
1853 // extract profile
1854 _ustrProfile.assignUtf8(pcszClearProfile, pFirstBackslash);
1855
1856 // V1.0.7 (2005-05-15) [pr]: Changed to case-insensitive compare as there are
1857 // a few broken packages out there
1858 if ( _ustrProfile.compareUtf8I("USER")
1859 && _ustrProfile.compareUtf8I("SYSTEM")
1860 )
1861 {
1862 while (pFirstBackslash)
1863 {
1864 ULONG cbProfile = pFirstBackslash - pcszClearProfile;
1865 if ( (cbProfile > 4)
1866 && (!strnicmp(pFirstBackslash - 4, ".INI", 4))
1867 )
1868 {
1869 _ustrProfile.assignUtf8(pcszClearProfile, pFirstBackslash);
1870 break;
1871 }
1872
1873 pFirstBackslash = strchr(pFirstBackslash + 1, '\\');
1874 }
1875 }
1876 }
1877
1878 if (pFirstBackslash)
1879 {
1880 // get application
1881 PCSZ pSecondBackslash;
1882 if (pSecondBackslash = strchr(pFirstBackslash + 2, '\\'))
1883 {
1884 // key specified:
1885 // extract application up to key
1886 _ustrApplication.assignUtf8(pFirstBackslash + 1, pSecondBackslash);
1887
1888 // extract key (all the rest)
1889 _ustrKey.assignUtf8(pSecondBackslash + 1);
1890 }
1891 else
1892 // key not specified:
1893 _ustrApplication.assignUtf8(pFirstBackslash + 1);
1894 }
1895
1896 if (!_ustrApplication())
1897 // any error:
1898 throw BSConfigExcpt(PRFEXCPT_SYNTAX, ustrClearProfile);
1899}
1900
1901/*
1902 *@@ Clear:
1903 * deletes the corresponding profile entry.
1904 *
1905 *@@added V0.9.5 (2000-08-26) [umoeller]
1906 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1907 *@@changed WarpIN V1.0.11 (2006-08-29) [pr]: fix entire app. delete @@fixes 833
1908 */
1909
1910int BSClearProfile::Clear(BSUniCodec &codecProcess, // in: codec for process codepage,
1911 HAB hab,
1912 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1913 const
1914{
1915 BOOL fOK = FALSE;
1916 HINI hini = NULLHANDLE,
1917 hini2Close = NULLHANDLE;
1918
1919 if (!_ustrProfile.compareUtf8("USER"))
1920 hini = HINI_USER;
1921 else if (!_ustrProfile.compareUtf8("SYSTEM"))
1922 hini = HINI_SYSTEM;
1923 else
1924 {
1925 CONVERT(&codecProcess, Profile);
1926 hini = PrfOpenProfile(hab,
1927 pcszProfile);
1928 hini2Close = hini;
1929 }
1930
1931 if (hini)
1932 {
1933 CONVERT(&codecProcess, Application);
1934 CONVERT(&codecProcess, Key);
1935
1936 ULONG cb = 0;
1937
1938 // WarpIN V1.0.11 (2006-08-29) [pr]: fix entire app. delete @@fixes 833
1939 if (strlen(pcszKey) == 0)
1940 pcszKey = NULL;
1941
1942 // does key exist?
1943 if (PrfQueryProfileSize(hini,
1944 pcszApplication,
1945 pcszKey, // can be NULL
1946 &cb))
1947 {
1948 // key exists:
1949 if (PrfWriteProfileString(hini,
1950 pcszApplication,
1951 pcszKey, // can be NULL
1952 NULL))
1953 fOK = TRUE;
1954 }
1955 else
1956 // key does not exist:
1957 fOK = TRUE;
1958 }
1959
1960 if (!fOK)
1961 {
1962 string strClear = DescribePrfKey(codecProcess);
1963 if (pLogFile)
1964 pLogFile->Write("Error deleting profile key \"%s\"",
1965 strClear.c_str());
1966
1967 // error:
1968 throw BSConfigExcpt(PRFEXCPT_PRFERROR, DescribePrfKey());
1969 }
1970
1971 if (pLogFile)
1972 {
1973 string strClear = DescribePrfKey(codecProcess);
1974 pLogFile->Write("Deleted profile key \"%s\"",
1975 strClear.c_str());
1976 }
1977
1978 return (1);
1979}
1980
1981/*
1982 *@@ AddToUndoList:
1983 * static helper method to create BSClearProfile
1984 * instances from the specified logger instance.
1985 * Note that this class method will be used both
1986 * for "CLEARPROFILE" tags specified in the script
1987 * as well as "WRITEPROFILE" tags which were actually
1988 * executed (written to a profile).
1989 *
1990 * The new BSClearProfile objects are appended to
1991 * the specified list.
1992 *
1993 * This returns the number of items created.
1994 */
1995
1996int BSClearProfile::AddToUndoList(list<BSConfigBase*> &List,
1997 BSClearPrfAttrsLogger &logger)
1998{
1999 // the logger in this case has a simple list of PSZs with all
2000 // the profile keys that were created, each of which is terminated
2001 // with a null character
2002
2003 PSZ pszLogStart = logger._pabLogString,
2004 pszLogThis = pszLogStart;
2005 int iCount = 0;
2006
2007 while (pszLogThis < pszLogStart + logger._cbLogString)
2008 {
2009 ULONG cbLogThis = strlen(pszLogThis);
2010 ustring ustr;
2011 ustr.assignUtf8(pszLogThis);
2012 List.push_back(new BSClearProfile(ustr));
2013 pszLogThis += cbLogThis + 1; // go beyond null byte
2014 iCount++;
2015 }
2016
2017 return (iCount);
2018}
2019
2020/* ******************************************************************
2021 *
2022 * BSWriteProfile class
2023 *
2024 ********************************************************************/
2025
2026/*
2027 *@@ BSWriteProfile:
2028 *
2029 * Syntax:
2030 *
2031 + WRITEPROFILE="profile\application\key|string"
2032 *
2033 *@@added V0.9.1 (2000-02-07) [umoeller]
2034 *@@changed V0.9.19 (2002-05-07) [umoeller]: added missing class init, now writeprofiles work again
2035 *@@changed V1.0.5 (2005-03-06) [pr]: Improved parsing of profiles with path names. @@fixes 633
2036 */
2037
2038BSWriteProfile::BSWriteProfile(const ustring &ustrWriteProfile)
2039 : BSProfileBase(CFGT_WRITEPROFILE, tBSWriteProfile)
2040{
2041 PCSZ pcszWriteProfile = ustrWriteProfile.GetBuffer();
2042
2043 // override class, this was still BSClearProfile due
2044 // to the constructor; this is also why writeprofiles
2045 // never worked V0.9.19 (2002-05-07) [umoeller]
2046 _Class = tBSWriteProfile;
2047
2048 PCSZ pSlash;
2049 if (pSlash = strchr(pcszWriteProfile, '|'))
2050 {
2051 // copy write data (after '|')
2052 _ustrWriteString.assignUtf8(pSlash + 1);
2053
2054 // get profile
2055 PCSZ pFirstBackslash;
2056 if (pFirstBackslash = strchr(pcszWriteProfile, '\\'))
2057 {
2058 // extract profile
2059 _ustrProfile.assignUtf8(pcszWriteProfile, pFirstBackslash);
2060
2061 if ( _ustrProfile.compareUtf8("USER")
2062 && _ustrProfile.compareUtf8("SYSTEM")
2063 )
2064 {
2065 while (pFirstBackslash)
2066 {
2067 ULONG cbProfile = pFirstBackslash - pcszWriteProfile;
2068 if ( (cbProfile > 4)
2069 && (!strnicmp(pFirstBackslash - 4, ".INI", 4))
2070 && (pFirstBackslash < pSlash)
2071 )
2072 {
2073 _ustrProfile.assignUtf8(pcszWriteProfile, pFirstBackslash);
2074 break;
2075 }
2076
2077 pFirstBackslash = strchr(pFirstBackslash + 1, '\\');
2078 }
2079 }
2080 }
2081
2082 if (pFirstBackslash)
2083 {
2084 // get application
2085 PCSZ pSecondBackslash;
2086 if (pSecondBackslash = strchr(pFirstBackslash + 2, '\\'))
2087 {
2088 // extract application
2089 _ustrApplication.assignUtf8(pFirstBackslash + 1, pSecondBackslash);
2090
2091 // extract key (up to '|')
2092 _ustrKey.assignUtf8(pSecondBackslash + 1, pSlash);
2093 }
2094 }
2095 }
2096
2097 if (!_ustrKey())
2098 // any error:
2099 throw BSConfigExcpt(PRFEXCPT_SYNTAX, ustrWriteProfile);
2100}
2101
2102/*
2103 *@@ Write:
2104 * this actually writes data to a profile, all
2105 * as specified by the member variables.
2106 *
2107 * Note that this stores the "done" stuff in
2108 * a BSClearPrfAttrsLogger for undoing later.
2109 *
2110 * Throws:
2111 * -- BSConfigExcpt.
2112 *
2113 *@@added V0.9.1 (2000-02-07) [umoeller]
2114 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
2115 */
2116
2117int BSWriteProfile::Write(BSUniCodec &codecProcess, // in: codec for process codepage,
2118 HAB hab, // in: anchor block (for PrfOpenProfile)
2119 BSClearPrfAttrsLogger *pLogger,
2120 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
2121 const
2122{
2123 BOOL fOK = FALSE;
2124 HINI hini = NULLHANDLE,
2125 hini2Close = NULLHANDLE;
2126
2127 if (!_ustrProfile.compareUtf8("USER"))
2128 hini = HINI_USER;
2129 else if (!_ustrProfile.compareUtf8("SYSTEM"))
2130 hini = HINI_SYSTEM;
2131 else
2132 {
2133 CONVERT(&codecProcess, Profile);
2134 if (!(hini = PrfOpenProfile(hab,
2135 pcszProfile)))
2136 throw BSConfigExcpt(PRFEXCPT_PRFOPENPROFILE, _ustrProfile);
2137
2138 hini2Close = hini;
2139 }
2140
2141 if (hini)
2142 {
2143 CONVERT(&codecProcess, Application);
2144 CONVERT(&codecProcess, Key);
2145 CONVERT(&codecProcess, WriteString);
2146 if (PrfWriteProfileString(hini,
2147 pcszApplication,
2148 pcszKey,
2149 pcszWriteString))
2150 {
2151 fOK = TRUE;
2152 }
2153 }
2154
2155 // recompose string for BSClearProfile
2156 ustring ustrClear = DescribePrfKey();
2157 string strClear = DescribePrfKey(codecProcess);
2158
2159 if (fOK)
2160 {
2161 if (pLogFile)
2162 pLogFile->Write("Wrote profile key \"%s\"",
2163 strClear.c_str());
2164
2165 if (pLogger)
2166 pLogger->Append(ustrClear);
2167 }
2168 else
2169 {
2170 // error:
2171 if (pLogFile)
2172 pLogFile->Write("Error writing profile key \"%s\"",
2173 strClear.c_str());
2174
2175 throw BSConfigExcpt(PRFEXCPT_PRFERROR, DescribePrfKey());
2176 }
2177
2178 return 1;
2179}
2180
2181/* ******************************************************************
2182 *
2183 * BSExecute class
2184 *
2185 ********************************************************************/
2186
2187/*
2188 *@@ BSExecute:
2189 * this constructor takes an EXECUTE attribute (of the PCK tag)
2190 * as input and sets up the instance data accordingly.
2191 *
2192 * Syntax:
2193 *
2194 + EXECUTE="[ context ] execfile params"
2195 *
2196 * Throws:
2197 * -- BSConfigExcpt.
2198 *
2199 *@@added V0.9.1 (2000-02-07) [umoeller]
2200 *@@changed V0.9.3 (2000-04-08) [umoeller]: "|" was a requirement, contradicting the docs; changed. Thanks, Cornelis Bockemhl.
2201 *@@changed V0.9.4 (2000-07-10) [umoeller]: _ulExecType wasn't always initialized; thanks Yuri Dario
2202 *@@changed V0.9.4 (2000-07-26) [umoeller]: now ORing the flags
2203 *@@changed V0.9.9 (2001-03-27) [umoeller]: fixed EXECUTE parameters
2204 */
2205
2206BSExecute::BSExecute(const ustring &ustrExecute,
2207 BSClassID &Class)
2208 : BSConfigBase(CFGT_EXECUTE, Class)
2209{
2210 BOOL fContextFound = FALSE,
2211 fContinue = TRUE;
2212 PCSZ pcszExecute = ustrExecute.GetBuffer();
2213 PCSZ pSearch = (PSZ)pcszExecute;
2214
2215 _ulExecType = 0;
2216 _arc = 0; // NO_ERROR
2217
2218 while (fContinue)
2219 {
2220 // skip leading spaces
2221 while ( (*pSearch)
2222 && (*pSearch == ' ')
2223 )
2224 pSearch++;
2225
2226 if (strncmp(pSearch, "CONFIGSYS", 9) == 0)
2227 {
2228 _ulExecType |= CFGT_CFGSYS;
2229 fContextFound = TRUE;
2230 pSearch += 9; // strlen("CONFIGSYS");
2231 }
2232 else if (strncmp(pSearch, "REGISTERCLASS", 13) == 0)
2233 {
2234 _ulExecType |= CFGT_REGISTERCLASS;
2235 fContextFound = TRUE;
2236 pSearch += 13; // strlen("REGISTERCLASS");
2237 }
2238 else if (strncmp(pSearch, "CREATEOBJECT", 12) == 0)
2239 {
2240 _ulExecType |= CFGT_CREATEOBJECT;
2241 fContextFound = TRUE;
2242 pSearch += 12; // strlen("CREATEOBJECT");
2243 }
2244 else
2245 // other: stop looping
2246 fContinue = FALSE;
2247 } // end while (fContinue)
2248
2249 if (!(*pSearch))
2250 throw BSConfigExcpt(EXEEXCPT_SYNTAX, ustrExecute);
2251
2252 // pSearch now points to the first non-space
2253 // character which does not introduces a keyword;
2254 // check if this is a "|" separator
2255
2256 if (*pSearch == '|')
2257 // skip '|'
2258 pSearch++;
2259
2260 // skip following spaces
2261 while ( (*pSearch)
2262 && (*pSearch == ' ')
2263 )
2264 pSearch++;
2265
2266 // NOW we finally point to the executable
2267
2268 if (!(*pSearch))
2269 throw BSConfigExcpt(EXEEXCPT_SYNTAX, ustrExecute);
2270
2271 // separate executable and parameters:
2272 // This can be separated by another '|',
2273 // or a space.
2274
2275 // NOTE: The '|' separator is used by the "resolved"
2276 // logger, from which BSDeExecute instances are
2277 // created on de-install. But the documentation states
2278 // spaces should be used... as long as a user doesn't
2279 // use spaces in the (unresolved) filename, we're fine.
2280 // For example we get:
2281 // 1) on install: $(1)\install.cmd PARAMETER
2282 // works nicely, and $(1) may contain spaces.
2283 // 2) Logger stores C:\PATH1 WITH SPACES\install.cmd|PARAMETER
2284 // in database.
2285 // 3) on deinstall, BSDeExecutes get created, and
2286 // we now have nice separation and get PARAMETER
2287 // properly separated.
2288 PCSZ p;
2289 if (!(p = strchr(pSearch, '|')))
2290 p = strchr(pSearch, ' ');
2291 if (p)
2292 {
2293 const char *pSep = p++; // V1.0.5 (2005-01-20) [pr]: @@fixes 624
2294 // we have a space --> parameters:
2295 while ( (*p)
2296 && (*p == ' ')
2297 )
2298 p++;
2299
2300 if (*p)
2301 {
2302 _ustrParams.assignUtf8(p);
2303 _ustrExecutable.assignUtf8(pSearch, pSep);
2304 }
2305 else
2306 _ustrExecutable.assignUtf8(pSearch);
2307 }
2308 else
2309 _ustrExecutable.assignUtf8(pSearch);
2310}
2311
2312/*
2313 *@@ DescribeType:
2314 * describes the current manipulator type to the GUI.
2315 *
2316 *@@added V0.9.9 (2001-03-27) [umoeller]
2317 */
2318
2319const char* BSExecute::DescribeType()
2320{
2321 return ("Execute program");
2322}
2323
2324/*
2325 *@@ DescribeData:
2326 * describes the current manipulator data to the GUI.
2327 *
2328 *@@added V0.9.9 (2001-03-27) [umoeller]
2329 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
2330 */
2331
2332ustring BSExecute::DescribeData()
2333{
2334 ustring ustr;
2335 ustr._printf("\"%s\"", _ustrExecutable.GetBuffer());
2336
2337 if (_ustrParams())
2338 {
2339 ustr.appendUtf8(" \"");
2340 ustr += _ustrParams;
2341 ustr.appendUtf8("\"");
2342 }
2343
2344 if (_ulExecType == 0)
2345 ustr.appendUtf8(" (no flags)");
2346 else
2347 {
2348 if (_ulExecType & CFGT_CFGSYS)
2349 ustr.appendUtf8(" CONFIGSYS");
2350 if (_ulExecType & CFGT_REGISTERCLASS)
2351 ustr.appendUtf8(" REGISTERCLASS");
2352 if (_ulExecType & CFGT_CREATEOBJECT)
2353 ustr.appendUtf8(" CREATEOBJECT");
2354 }
2355
2356 return (ustr);
2357}
2358
2359/*
2360 *@@ Execute:
2361 * executes the member program. This does not return
2362 * until the program terminates. As a result, do not
2363 * call this on a PM thread, because this gets blocked.
2364 *
2365 * Throws:
2366 * -- BSConfigExcpt.
2367 *
2368 *@@added V0.9.1 (2000-02-07) [umoeller]
2369 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
2370 *@@changed V1.0.5 (2005-01-25) [pr]: Change directory to that of executable
2371 *@@changed WarpIN V1.0.10 (2006-04-01) [pr]: Set title in doshStartSession call
2372 */
2373
2374int BSExecute::Execute(BSUniCodec &codecProcess, // in: codec for process codepage,
2375 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
2376{
2377 string strTitle;
2378 strTitle.assignUtf8(&codecProcess, _ustrExecutable);
2379 string strParams = "/c ";
2380 strParams.appendUtf8(&codecProcess, _ustrExecutable);
2381 if (_ustrParams())
2382 {
2383 strParams += " ";
2384 strParams.appendUtf8(&codecProcess, _ustrParams);
2385 }
2386
2387 // V1.0.7 (2005-05-30) [pr]: This doesn't work. Some packages rely on the current
2388 // directory not being changed, so you cannot win whatever you do. In any case, the
2389 // code below assumes it is always a path'd executable, which is not always the case.
2390 // Perhaps we should just set BEGINLIBPATH here instead which will allow newly
2391 // installed EXEs to find their DLLs.
2392 //
2393 // V1.0.5 (2005-01-26) [pr]: Change directory to that of executable. @@fixes 626.
2394 // We remove any leading quotes and just leave the directory name, excluding a
2395 // trailing slash, unless it is a root directory.
2396#if 0
2397 string strDir;
2398 strDir.assignUtf8(&codecProcess, _ustrExecutable);
2399 strDir = strDir.substr(strDir.find_first_not_of("\"'"));
2400 size_type pos = strDir.rfind('\\', 0);
2401 if (pos != string::npos)
2402 {
2403 strDir.erase(pos);
2404 if (strDir.size() == 2 && strDir[1] == ':')
2405 strDir += '\\';
2406
2407 doshSetCurrentDir(strDir.c_str());
2408 }
2409#endif
2410
2411 ULONG sid = 0;
2412 PID pid = 0;
2413 if (_arc = doshQuickStartSession("cmd.exe",
2414 (PSZ)strParams.c_str(),
2415 (PSZ)strTitle.c_str(),
2416 SSF_TYPE_DEFAULT, // session type
2417 FALSE, // foreground
2418 0, // auto-close, visible
2419 TRUE, // wait
2420 &sid,
2421 &pid,
2422 NULL))
2423 {
2424 if (pLogFile)
2425 pLogFile->Write("Error %d executing \"CMD.EXE %s\"",
2426 _arc,
2427 strParams.c_str());
2428
2429 throw BSConfigExcpt(EXEEXCPT_DOSERROR, _arc);
2430 }
2431
2432 if (pLogFile)
2433 pLogFile->Write("Executed \"CMD.EXE %s\"",
2434 strParams.c_str());
2435
2436 return (0);
2437}
2438
2439/* ******************************************************************
2440 *
2441 * BSDeExecute class
2442 *
2443 ********************************************************************/
2444
2445/*
2446 *@@ BSDeExecute:
2447 * constructor.
2448 *
2449 *@@added V0.9.16 (2001-12-08) [umoeller]
2450 */
2451
2452BSDeExecute::BSDeExecute(const ustring &ustrDeExecute)
2453 : BSExecute(ustrDeExecute, tBSDeExecute)
2454{
2455};
2456
2457/*
2458 *@@ DescribeType:
2459 * describes the current manipulator type to the GUI.
2460 *
2461 *@@added V0.9.2 (2000-02-19) [umoeller]
2462 */
2463
2464const char* BSDeExecute::DescribeType()
2465{
2466 return ("External program for deinstall");
2467}
2468
2469/*
2470 *@@ AddToUndoList:
2471 * static helper method to create BSDeExecute instances from
2472 * the specified logger instance.
2473 *
2474 * The new BSKillProcess objects are appended to
2475 * the specified list.
2476 *
2477 * This returns the number of items created.
2478 *
2479 * This isn't really an "Undo" method like the other
2480 * static AddToUndoList methods (for the other classes),
2481 * but has been named like this for conformity. This
2482 * is during package de-install to create the same
2483 * BSDeExecute list which was initially created from
2484 * the script so that processes can be killed during
2485 * de-install as well.
2486 *
2487 *@@added V0.9.9 (2001-03-27) [umoeller]
2488 */
2489
2490int BSDeExecute::AddToUndoList(list <BSConfigBase*> &List,
2491 BSDeExecuteResolvedLogger &logger)
2492{
2493 PSZ pszLogStart = logger._pabLogString,
2494 pszLogThis = pszLogStart;
2495 int iCount = 0;
2496
2497 while (pszLogThis < pszLogStart + logger._cbLogString)
2498 {
2499 ULONG cbLogThis = strlen(pszLogThis);
2500 ustring ustr;
2501 ustr.assignUtf8(pszLogThis);
2502 List.push_back(new BSDeExecute(ustr));
2503 pszLogThis += cbLogThis + 1; // go beyond null byte
2504 iCount++;
2505 }
2506
2507 return (iCount);
2508}
2509
2510/* ******************************************************************
2511 *
2512 * BSKillProcess class
2513 *
2514 ********************************************************************/
2515
2516/*
2517 *@@ BSKillProcess:
2518 *
2519 * Syntax:
2520 *
2521 + KILLPROCESS="filename"
2522 *
2523 * Throws:
2524 * -- BSConfigExcpt.
2525 *
2526 *@@added V0.9.1 (2000-02-12) [umoeller]
2527 */
2528
2529BSKillProcess::BSKillProcess(const ustring &ustrKillProcess)
2530 : BSConfigBase(CFGT_KILLPROCESS, tBSKillProcess)
2531{
2532 if (!ustrKillProcess())
2533 throw BSConfigExcpt(KILLEXCPT_SYNTAX, ustrKillProcess);
2534
2535 _ustrKillProcess = ustrKillProcess;
2536}
2537
2538/*
2539 *@@ DescribeType:
2540 * describes the current manipulator type to the GUI.
2541 *
2542 *@@added V0.9.4 (2000-07-01) [umoeller]
2543 */
2544
2545const char* BSKillProcess::DescribeType()
2546{
2547 return ("Kill process");
2548}
2549
2550/*
2551 *@@ DescribeData:
2552 * describes the current manipulator data to the GUI.
2553 *
2554 *@@added V0.9.4 (2000-07-01) [umoeller]
2555 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
2556 */
2557
2558ustring BSKillProcess::DescribeData()
2559{
2560 return _ustrKillProcess;
2561}
2562
2563/*
2564 *@@ AddToUndoList:
2565 * static helper method to create BSKillProcess
2566 * instances from the specified logger instance.
2567 *
2568 * The new BSKillProcess objects are appended to
2569 * the specified list.
2570 *
2571 * This returns the number of items created.
2572 *
2573 * This isn't really an "Undo" method like the other
2574 * static AddToUndoList methods (for the other classes),
2575 * but has been named like this for conformity. This
2576 * is during package de-install to create the same
2577 * BSKillProcess list which was initially created from
2578 * the script so that processes can be killed during
2579 * de-install as well.
2580 *
2581 *@@added V0.9.4 (2000-07-01) [umoeller]
2582 */
2583
2584int BSKillProcess::AddToUndoList(list<BSConfigBase*> &List,
2585 BSKillProcessAttrsLogger &logger)
2586{
2587 // the logger in this case has a simple list of PSZs with all
2588 // the executable names that were created, each of which is
2589 // terminated with a null character
2590
2591 PSZ pszLogStart = logger._pabLogString,
2592 pszLogThis = pszLogStart;
2593 int iCount = 0;
2594
2595 while (pszLogThis < pszLogStart + logger._cbLogString)
2596 {
2597 ULONG cbLogThis = strlen(pszLogThis);
2598 ustring ustr;
2599 ustr.assignUtf8(pszLogThis);
2600 List.push_back(new BSKillProcess(ustr));
2601 pszLogThis += cbLogThis + 1; // go beyond null byte
2602 iCount++;
2603 }
2604
2605 return (iCount);
2606}
2607
2608
Note: See TracBrowser for help on using the repository browser.