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

Last change on this file since 284 was 283, checked in by pr, 20 years ago

Case-insensitive compare for USER and SYSTEM in CLEARPROFILE

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 78.1 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-2001 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 */
620
621BSConfigSys::BSConfigSys() : BSRoot(tBSConfigSys)
622{
623 _pszContent = NULL;
624
625 /* sprintf(_szFilename, "%c:\\config.sys", doshQueryBootDrive());
626 // now read CONFIG.SYS file to initialize the dlg items
627 APIRET arc = doshLoadTextFile(_szFilename, &_pszContent); */
628
629 APIRET arc = csysLoadConfigSys(NULL, // default CONFIG.SYS
630 &_pszContent);
631
632 if (arc != NO_ERROR)
633 throw BSConfigExcpt(CFGEXCPT_OPEN, arc);
634
635 _fDirty = FALSE;
636}
637
638/*
639 *@@ ~ConfigSys:
640 * the destructor.
641 *
642 * This does _not_ write the file. Use BSConfigSys::Flush()
643 * before deleting an instance of this.
644 */
645
646BSConfigSys::~BSConfigSys()
647{
648 if (_pszContent)
649 free(_pszContent);
650}
651
652/*
653 *@@ Manipulate:
654 * this monster method changes the data in our memory copy of
655 * CONFIG.SYS according to the BSCfgSysManip object, which you must
656 * have created before. See BSCfgSysManip::BSCfgSysManip for a
657 * description of this usage.
658 *
659 * This also takes a BSCfgSysDoneLogger as input where all the
660 * changes made to the CONFIG.SYS memory copy are logged. This
661 * logger can then be passed to BSConfigSys::Undo to have the
662 * changes undone again.
663 *
664 * Call BSConfigSys::Flush to have CONFIG.SYS written back to disk.
665 *
666 * Returns NO_ERROR if everything was OK or an error code.
667 *
668 *@@changed V0.9.18 (2002-03-08) [umoeller]: adjusted for Unicode; added codec
669 */
670
671int BSConfigSys::Manipulate(BSUniCodec &codecProcess, // in: codec for process codepage
672 BSCfgSysManip &Manip, // in: manipulator object
673 BSCfgSysDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
674 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
675{
676 int irc = 0;
677
678 XSTRING strLogger;
679 xstrInit(&strLogger, 0);
680
681 CONFIGMANIP cm;
682 memset(&cm, 0, sizeof(cm));
683
684 cm.iReplaceMode = Manip._iReplaceMode;
685
686 string strUniqueSearchString2(&codecProcess, Manip._ustrUniqueSearchString2);
687 cm.pszUniqueSearchString2 = strUniqueSearchString2.c_str();
688
689 cm.iVertical = Manip._iVertical;
690
691 string strVerticalSearchString(&codecProcess, Manip._ustrVerticalSearchString);
692 cm.pszVerticalSearchString = strVerticalSearchString.c_str();
693
694 string strNewLine(&codecProcess, Manip._ustrNewLine);
695 cm.pszNewLine = strNewLine.c_str();
696
697 irc = csysManipulate(&_pszContent,
698 &cm,
699 &_fDirty,
700 &strLogger);
701
702 // now parse the logger...
703 if (strLogger.ulLength)
704 {
705 // something to be logged:
706 PSZ p = strLogger.psz;
707
708 while (p)
709 {
710 PSZ pEOL;
711 if ( (pEOL = strhFindEOL(p, NULL))
712 && (*pEOL)
713 )
714 {
715 string strTemp(p, pEOL);
716
717 if (strTemp())
718 {
719 if (pLogFile)
720 // write to log file
721 pLogFile->Write("Updated CONFIG.SYS: \"%s\"",
722 strTemp.c_str());
723
724 if (pLogger)
725 {
726 // write to "done" logger:
727 ustring ustr(&codecProcess, strTemp);
728 pLogger->Append(ustr);
729 }
730 }
731 else
732 break;
733
734 p = pEOL + 1;
735 }
736 else
737 break;
738 }
739 }
740
741 xstrClear(&strLogger);
742
743 return (irc);
744}
745
746/*
747 *@@ Flush:
748 * this rewrites the CONFIG.SYS file on disk with the
749 * data we have in memory.
750 *
751 * This makes a backup copy in "CONFIG.003" style if
752 * (pszBackup != NULL). See doshCreateBackupFileName
753 * for details.
754 *
755 * Returns:
756 *
757 * -- 0: contents were dirty, written back to disk.
758 *
759 * -- 1: no error, but contents were clean, so no write-back
760 * was needed.
761 *
762 * Throws:
763 * -- BSConfigExcpt(CFGEXCPT_WRITE, APIRET).
764 *
765 *@@changed V0.9.3 (2000-05-03) [umoeller]: added more error checking
766 *@@changed V0.9.3 (2000-05-12) [umoeller]: added pszBackup
767 *@@changed V0.9.6 (2000-10-27) [umoeller]: added check if contents are dirty
768 */
769
770int BSConfigSys::Flush(string *pstrBackup, // in/out: create backup?
771 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
772 const
773{
774 int irc = 0;
775
776 if (_fDirty)
777 {
778 PSZ pszBackup = NULL;
779 CHAR szBackup[CCHMAXPATH];
780 if (pstrBackup)
781 pszBackup = szBackup;
782
783 APIRET arc = csysWriteConfigSys(NULL, // default _szFilename,
784 _pszContent,
785 pszBackup); // create backup
786
787 if (arc)
788 {
789 if (pLogFile)
790 pLogFile->Write("Error %d occurred writing CONFIG.SYS back to disk",
791 arc);
792
793 throw BSConfigExcpt(CFGEXCPT_WRITE, arc);
794 }
795
796 if (pLogFile)
797 pLogFile->Write("CONFIG.SYS file written back to disk, backup is \"%s\"",
798 pszBackup);
799
800 if (pstrBackup)
801 pstrBackup->assign(szBackup);
802 }
803 else
804 irc = 1;
805
806 return (irc);
807}
808
809/* ******************************************************************
810 *
811 * BSRegisterClass class
812 *
813 ********************************************************************/
814
815/*
816 *@@ BSRegisterClass:
817 * this constructor translates a REGISTERCLASS attribute (as used
818 * in the PCK tag and stored in the database) into the BSRegisterClass
819 * instance data.
820 *
821 * Syntax:
822 *
823 + REGISTERCLASS="classname|dllpath"
824 *
825 * Throws:
826 * -- BSConfigExcpt.
827 */
828
829BSRegisterClass::BSRegisterClass(const ustring &ustrRegisterClass)
830 : BSConfigBase(CFGT_REGISTERCLASS, tBSRegisterClass)
831{
832 // find separator
833 PCSZ pcszRegisterClass = ustrRegisterClass.GetBuffer();
834 PCSZ pBegin;
835 if (!(pBegin = pcszRegisterClass))
836 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
837
838 PCSZ pEnd;
839 if (!(pEnd = strchr(pBegin, '|')))
840 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
841
842 // strip trailing spaces
843 PCSZ pEnd2 = pEnd;
844 while ((*pEnd2 == ' ') && (pEnd2 > pcszRegisterClass))
845 pEnd2--;
846
847 _ustrClassName.assignUtf8(pBegin, pEnd2);
848 if (!_ustrClassName())
849 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
850
851 pBegin = pEnd + 1;
852 // strip leading spaces
853 while ((*pBegin) && (*pBegin == ' '))
854 pBegin++;
855 _ustrModule.assignUtf8(pBegin);
856 if (!_ustrModule())
857 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
858}
859
860/*
861 *@@ DescribeType:
862 * describes the current manipulator type to the GUI.
863 *
864 *@@added V0.9.9 (2001-03-27) [umoeller]
865 */
866
867const char* BSRegisterClass::DescribeType()
868{
869 return ("WPS class registration");
870}
871
872/*
873 *@@ DescribeData:
874 * describes the current manipulator data to the GUI.
875 *
876 *@@added V0.9.9 (2001-03-27) [umoeller]
877 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
878 */
879
880ustring BSRegisterClass::DescribeData()
881{
882 ustring str = _ustrClassName;
883 str.appendUtf8(" in ");
884 str += _ustrModule;
885
886 return (str);
887}
888
889/*
890 *@@ IsRegistered:
891 * this returns TRUE if a class of the same WPS class name
892 * as this instance is already registered with the WPS.
893 * In that case, the module of the registered class is
894 * copied into strModule.
895 *
896 * This throws a BSConfigExcpt with REGEXCPT_QUERYCLASSLIST
897 * if the class list could not be queried.
898 *
899 *@@changed V0.9.18 (2002-03-08) [umoeller]: now using string for buffer, added codec
900 */
901
902bool BSRegisterClass::IsRegistered(BSUniCodec &codecProcess, // in: codec for process codepage
903 ustring &ustrModule)
904 const
905{
906 BOOL fInstalled = FALSE;
907 PBYTE pClassList,
908 pClassThis = 0;
909 if (pClassList = winhQueryWPSClassList())
910 {
911 string strClassName(&codecProcess, _ustrClassName);
912 if ((pClassThis = winhQueryWPSClass(pClassList, strClassName.c_str())))
913 {
914 fInstalled = TRUE;
915 ustrModule.assignCP(&codecProcess, ((POBJCLASS)pClassThis)->pszModName);
916 }
917
918 free(pClassList);
919 }
920 else
921 throw BSConfigExcpt(REGEXCPT_QUERYCLASSLIST, 0);
922
923 return (fInstalled);
924}
925
926/*
927 *@@ Register:
928 * this attempts to register the class.
929 *
930 * If (fReplace == TRUE), we do not call
931 * BSRegisterClass::IsRegistered before registering
932 * this, i.e. we will always register the class,
933 * even if it's already registered.
934 *
935 * If (fReplace == FALSE) and BSRegisterClass::IsRegistered
936 * returned TRUE, we throw a BSConfigExcpt with
937 * REGEXCPT_ALREADYREGISTERED and pszSubstr set to the
938 * file name of the registered DLL. Note that IsRegistered might
939 * in turn throw BSConfigExcpt with REGEXCPT_QUERYCLASSLIST.
940 *
941 * If registering the class failed, this throws a
942 * BSConfigExcpt with REGEXCPT_REGISTER and iData set
943 * to the APIRET of winhRegisterClass.
944 *
945 * This method can take a BSDoneLoggerBase object as input, which
946 * can later be used with the BSDeregisterClass::AddToUndoList
947 * static class method to easily create a list of BSDeregisterClass
948 * objects to undo the changes made.
949 *
950 * Example usage (exception handling omitted):
951 + BSRegisterDoneLogger logger;
952 + // create logger instance
953 + BSRegisterClass RegClass("XFolder|C:\XFOLDER\XFLDR.DLL");
954 + // create BSRegisterClass instance:
955 + RegClass.Register(TRUE, logger);
956 + ... // register more classes with the same logger
957 +
958 + // now create undo list
959 + list<BSDeregisterClass*> List;
960 + BSDeregisterClass::AddToUndoList(List, logger);
961 + list<BSDeregisterClass*>::iterator DeregStart = List.begin(),
962 + DeregEnd = List.end();
963 + for (; DeregStart != DeregEnd; DeregStart++)
964 + (**DeregStart).Deregister;
965 *
966 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
967 *@@changed V0.9.18 (2002-03-08) [umoeller]: added missing log file entry
968 */
969
970int BSRegisterClass::Register(BSUniCodec &codecProcess, // in: codec for process codepage
971 bool fReplace,
972 BSRegisterDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
973 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
974 const
975{
976 int irc = 0;
977
978 if (fReplace == FALSE)
979 {
980 ustring ustrModule;
981 if (IsRegistered(codecProcess, ustrModule))
982 throw BSConfigExcpt(REGEXCPT_ALREADYREGISTERED, ustrModule);
983 }
984
985 CONVERT(&codecProcess, ClassName);
986 CONVERT(&codecProcess, Module);
987
988 CHAR szBuf[1000];
989 APIRET arc = winhRegisterClass(pcszClassName,
990 pcszModule,
991 szBuf,
992 sizeof(szBuf));
993 // always record in logger, even if failed,
994 // because the class is in the class list anyway
995 if (pLogger)
996 pLogger->Append(_ustrClassName);
997
998 if (arc != NO_ERROR)
999 {
1000 // this was missing V0.9.18 (2002-03-08) [umoeller]
1001 if (pLogFile)
1002 pLogFile->Write("Error %d registering WPS class \"%s\"",
1003 arc,
1004 pcszClassName);
1005
1006 throw BSConfigExcpt(REGEXCPT_REGISTER, arc);
1007 }
1008
1009 // this was missing V0.9.18 (2002-03-08) [umoeller]
1010 if (pLogFile)
1011 pLogFile->Write("Registered WPS class \"%s\"",
1012 pcszClassName);
1013
1014 return (irc);
1015}
1016
1017/* ******************************************************************
1018 *
1019 * BSDeregisterClass class
1020 *
1021 ********************************************************************/
1022
1023/*
1024 *@@ BSDeregisterClass:
1025 * the constructor, which in this case takes a simple
1026 * PSZ class name as input.
1027 */
1028
1029BSDeregisterClass::BSDeregisterClass(const ustring &ustrDeregisterClass)
1030 : BSConfigBase(CFGT_DEREGISTERCLASS, tBSDeregisterClass)
1031{
1032 _ustrClassName = ustrDeregisterClass;
1033}
1034
1035/*
1036 *@@ DescribeType:
1037 * describes the current manipulator type to the GUI.
1038 *
1039 *@@added V0.9.2 (2000-02-19) [umoeller]
1040 */
1041
1042const char* BSDeregisterClass::DescribeType()
1043{
1044 return ("WPS class deregistration");
1045}
1046
1047/*
1048 *@@ DescribeData:
1049 * describes the current manipulator data to the GUI.
1050 *
1051 *@@added V0.9.2 (2000-02-19) [umoeller]
1052 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1053 */
1054
1055ustring BSDeregisterClass::DescribeData()
1056{
1057 return (_ustrClassName);
1058}
1059
1060/*
1061 *@@ Deregister:
1062 * this attempts to deregister the class.
1063 *
1064 * Throws:
1065 * -- BSConfigExcpt.
1066 *
1067 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1068 */
1069
1070int BSDeregisterClass::Deregister(BSUniCodec &codecProcess, // in: codec for process codepage
1071 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1072 const
1073{
1074 int irc = 0;
1075
1076 CONVERT(&codecProcess, ClassName); // creates local string strXXX, PCSZ pcszXXX
1077
1078 if (!WinDeregisterObjectClass(pcszClassName))
1079 {
1080 if (pLogFile)
1081 pLogFile->Write("An error occurred deregistering WPS class \"%s\"",
1082 pcszClassName);
1083
1084 throw BSConfigExcpt(REGEXCPT_DEREGISTER, _ustrClassName);
1085 }
1086
1087 if (pLogFile)
1088 pLogFile->Write("Deregistered WPS class \"%s\"",
1089 pcszClassName);
1090
1091 return (irc);
1092}
1093
1094/*
1095 *@@ AddToUndoList:
1096 * static helper method to create BSDeregisterClass
1097 * instances from the logger instance that was
1098 * previously used with BSRegisterClass::Register.
1099 *
1100 * The new BSDeregisterClass objects are appended to
1101 * the specified list.
1102 *
1103 * See BSRegisterClass::Register for an example usage.
1104 *
1105 * This returns the number of items created.
1106 */
1107
1108int BSDeregisterClass::AddToUndoList(list<BSConfigBase*> &List,
1109 BSRegisterDoneLogger &logger)
1110{
1111 // the logger in this case has a simple list of PSZs with all
1112 // the class names that were registered, each of which is terminated
1113 // with a null character
1114
1115 PSZ pszLogStart = logger._pabLogString,
1116 pszLogThis = pszLogStart;
1117 int iCount = 0;
1118
1119 while (pszLogThis < pszLogStart + logger._cbLogString)
1120 {
1121 ULONG cbLogThis = strlen(pszLogThis);
1122 ustring ustr;
1123 ustr.assignUtf8(pszLogThis);
1124 List.push_back(new BSDeregisterClass(ustr));
1125 pszLogThis += cbLogThis + 1; // go beyond null byte
1126 iCount++;
1127 }
1128
1129 return (iCount);
1130}
1131
1132/* ******************************************************************
1133 *
1134 * BSReplaceClass class
1135 *
1136 ********************************************************************/
1137
1138/*
1139 *@@ BSReplaceClassBase:
1140 * this constructor translates a REPLACECLASS attribute (as used
1141 * in the PCK tag and stored in the database) into the BSReplaceClass
1142 * instance data.
1143 *
1144 * Syntax:
1145 *
1146 + REPLACECLASS="oldclassname|newclassname"
1147 *
1148 *@@changed V0.9.19 (2002-05-07) [umoeller]: changed inheritance hierarchy here
1149 */
1150
1151BSReplaceClassBase::BSReplaceClassBase(const ustring &ustrReplaceClass,
1152 ULONG cfgt,
1153 BSClassID &Class)
1154 : BSConfigBase(cfgt, Class)
1155{
1156 PCSZ pcszReplaceClass = ustrReplaceClass.GetBuffer();
1157
1158 // find separator
1159 PCSZ pBegin;
1160 if (!(pBegin = pcszReplaceClass))
1161 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1162
1163 PCSZ pEnd;
1164 if (!(pEnd = strchr(pBegin, '|')))
1165 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1166
1167 // strip trailing spaces
1168 PCSZ pEnd2 = pEnd;
1169 while ((*pEnd2 == ' ') && (pEnd2 > pcszReplaceClass))
1170 pEnd2--;
1171
1172 _ustrOldClassName.assignUtf8(pBegin, pEnd2);
1173 if (!_ustrOldClassName())
1174 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1175
1176 pBegin = pEnd + 1;
1177 // strip leading spaces
1178 while ((*pBegin) && (*pBegin == ' '))
1179 pBegin++;
1180 _ustrNewClassName.assignUtf8(pBegin);
1181 if (!_ustrNewClassName())
1182 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1183}
1184
1185/*
1186 *@@ DescribeType:
1187 * describes the current manipulator type to the GUI.
1188 *
1189 *@@added V0.9.2 (2000-02-19) [umoeller]
1190 */
1191
1192const char* BSReplaceClass::DescribeType()
1193{
1194 return ("WPS class replacement");
1195}
1196
1197/*
1198 *@@ DescribeData:
1199 * describes the current manipulator data to the GUI.
1200 *
1201 *@@added V0.9.2 (2000-02-19) [umoeller]
1202 *@@changed V0.9.5 (2000-08-26) [umoeller]: UNIQUE wasn't reported right
1203 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1204 */
1205
1206ustring BSReplaceClass::DescribeData()
1207{
1208 ustring str = _ustrOldClassName;
1209 str.appendUtf8(" with ");
1210 str += _ustrNewClassName;
1211
1212 return (str);
1213}
1214
1215/*
1216 *@@ Replace:
1217 * this attempts to replace the class or undo
1218 * an existing replacement (if fReplace == FALSE).
1219 *
1220 * If replacing the class failed, this throws a
1221 * BSConfigExcpt with REGEXCPT_REPLACE.
1222 *
1223 * Example usage (exception handling omitted):
1224 + BSReplaceDoneLogger logger;
1225 + // create logger instance
1226 + BSReplaceClass ReplClass("WPFolder;XFolder");
1227 + // create BSReplaceClass instance:
1228 + ReplClass.Replace(TRUE, logger);
1229 + ... // replace more classes with the same logger
1230 +
1231 + // now create undo list
1232 + list<BSUnreplaceClass*> List;
1233 + BSUnreplaceClass::AddToUndoList(List, logger);
1234 + list<BSUnreplaceClass*>::iterator UnrplStart = List.begin(),
1235 + UnrplEnd = List.end();
1236 + for (; UnrplStart != UnrplEnd; UnrplStart++)
1237 + (**UnrplStart).Unreplace;
1238 *
1239 *@@changed V0.9.1 (2000-01-05) [umoeller]: finally added logging, which was missing
1240 *@@changed V0.9.9 (2001-03-30) [umoeller]: fixed wrong logging if replace failed
1241 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1242 */
1243
1244int BSReplaceClass::Replace(BSUniCodec &codecProcess, // in: codec for process codepage
1245 BSReplaceDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
1246 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1247 const
1248{
1249 int irc = 0;
1250
1251 CONVERT(&codecProcess, OldClassName);
1252 CONVERT(&codecProcess, NewClassName);
1253
1254 BOOL brc = WinReplaceObjectClass(pcszOldClassName,
1255 pcszNewClassName,
1256 TRUE); // replace
1257 // always record in logger, even if failed,
1258 // because the class is in the class list anyway
1259 // V0.9.9 (2001-03-30) [umoeller]
1260 if (pLogger)
1261 {
1262 ustring ustr2Append(_ustrOldClassName);
1263 ustr2Append.appendUtf8("|");
1264 ustr2Append += _ustrNewClassName;
1265 pLogger->Append(ustr2Append);
1266 }
1267
1268
1269 if (!brc)
1270 {
1271 if (pLogFile)
1272 pLogFile->Write("An error occurred replacing WPS class \"%s\" with \"%s\"",
1273 pcszOldClassName,
1274 pcszNewClassName);
1275
1276 throw BSConfigExcpt(REGEXCPT_REPLACE, 0);
1277 }
1278
1279 // success:
1280 if (pLogFile)
1281 pLogFile->Write("Replaced WPS class \"%s\" with \"%s\"",
1282 pcszOldClassName,
1283 pcszNewClassName);
1284
1285 return (irc);
1286}
1287
1288/* ******************************************************************
1289 *
1290 * BSUnreplaceClass class
1291 *
1292 ********************************************************************/
1293
1294/*
1295 *@@ DescribeType:
1296 * describes the current manipulator type to the GUI.
1297 *
1298 *@@added V0.9.2 (2000-02-19) [umoeller]
1299 */
1300
1301const char* BSUnreplaceClass::DescribeType()
1302{
1303 return ("WPS class un-replacement");
1304}
1305
1306/*
1307 *@@ DescribeData:
1308 * describes the current manipulator data to the GUI.
1309 *
1310 *@@added V0.9.2 (2000-02-19) [umoeller]
1311 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1312 */
1313
1314ustring BSUnreplaceClass::DescribeData()
1315{
1316 ustring ustr = _ustrOldClassName;
1317 ustr.appendUtf8(" with ");
1318 ustr += _ustrNewClassName;
1319
1320 return (ustr);
1321}
1322
1323/*
1324 *@@ Unreplace:
1325 * this attempts to unreplace the class.
1326 * Throws a BSConfigExcpt upon failure.
1327 *
1328 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1329 */
1330
1331int BSUnreplaceClass::Unreplace(BSUniCodec &codecProcess, // in: codec for process codepage,
1332 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1333 const
1334{
1335 int irc = 0;
1336
1337 CONVERT(&codecProcess, OldClassName);
1338 CONVERT(&codecProcess, NewClassName);
1339
1340 if (!WinReplaceObjectClass(pcszOldClassName,
1341 pcszNewClassName,
1342 FALSE))
1343 {
1344 if (pLogFile)
1345 pLogFile->Write("Error undoing WPS class replacement of \"%s\" with \"%s\"",
1346 pcszOldClassName,
1347 pcszNewClassName);
1348
1349 throw BSConfigExcpt(REGEXCPT_UNREPLACE, 0);
1350 }
1351
1352 // success:
1353 if (pLogFile)
1354 pLogFile->Write("Undid WPS class replacement of \"%s\" with \"%s\"",
1355 pcszOldClassName,
1356 pcszNewClassName);
1357
1358 return (irc);
1359}
1360
1361/*
1362 *@@ AddToUndoList:
1363 * static helper method to create BSUnreplaceClass
1364 * instances from the logger instance that was
1365 * previously used with BSRegisterClass::Register.
1366 *
1367 * The new BSUnreplaceClass objects are appended to
1368 * the specified list.
1369 *
1370 * See BSReplaceClass::Replace for an example usage.
1371 *
1372 * This returns the number of items created.
1373 */
1374
1375int BSUnreplaceClass::AddToUndoList(list<BSConfigBase*> &List,
1376 BSReplaceDoneLogger &logger)
1377{
1378 // the logger in this case has a simple list of PSZs with all
1379 // the class names that were registered, each of which is terminated
1380 // with a null character
1381
1382 PSZ pszLogStart = logger._pabLogString,
1383 pszLogThis = pszLogStart;
1384 int iCount = 0;
1385
1386 while (pszLogThis < pszLogStart + logger._cbLogString)
1387 {
1388 ULONG cbLogThis = strlen(pszLogThis);
1389 ustring ustr;
1390 ustr.assignUtf8(pszLogThis);
1391 List.push_back(new BSUnreplaceClass(ustr));
1392 // this calls the inherited BSReplaceClass
1393 // constructor, which will parse the thing
1394 pszLogThis += cbLogThis + 1; // go beyond null byte
1395 iCount++;
1396 }
1397
1398 return (iCount);
1399}
1400
1401/* ******************************************************************
1402 *
1403 * BSCreateWPSObject class
1404 *
1405 ********************************************************************/
1406
1407/*
1408 *@@ BSCreateWPSObject:
1409 * this constructor translates a CREATEOBJECT attribute (as used
1410 * in the PCK tag and stored in the database) into the BSCreateWPSObject
1411 * instance data.
1412 *
1413 * Syntax:
1414 *
1415 + CREATEOBJECT="[REPLACE] classname|title|location[|config]]"
1416 *
1417 * Throws:
1418 * -- BSConfigExcpt.
1419 *
1420 *@@changed V0.9.3 (2000-04-08) [umoeller]: "REPLACE" wasn't evaluated; fixed. Thanks, Cornelis Bockemhl.
1421 *@@changed V0.9.15 (2001-08-26) [umoeller]: added WPOEXCPT_INVALIDLOCATION checks
1422 *@@changed V0.9.19 (2002-04-14) [umoeller]: REPLACE was never detected, fixed
1423 */
1424
1425BSCreateWPSObject::BSCreateWPSObject(const ustring &ustrCreateObject)
1426 : BSConfigBase(CFGT_CREATEOBJECT, tBSCreateWPSObject)
1427{
1428 PCSZ pcszCreateObject = ustrCreateObject.GetBuffer();
1429
1430 // extract class name
1431 PCSZ pBegin;
1432 if (!(pBegin = pcszCreateObject))
1433 throw BSConfigExcpt(WPOEXCPT_NOCLASS, ustrCreateObject);
1434
1435 // if (!strcmp(pBegin, "REPLACE ")) BUZZZZ WRONG V0.9.19 (2002-04-14) [umoeller]
1436 if (!memcmp(pBegin, "REPLACE ", 8))
1437 {
1438 // added V0.9.3 (2000-04-08) [umoeller]
1439 _fReplace = TRUE;
1440 pBegin += 7;
1441 while (*pBegin == ' ')
1442 pBegin++;
1443 }
1444 else
1445 _fReplace = FALSE;
1446
1447 PSZ pEnd;
1448 if (pEnd = strchr(pBegin, '|'))
1449 {
1450 _ustrClassName.assignUtf8(pBegin, pEnd);
1451
1452 // extract title
1453 pBegin = pEnd + 1;
1454 if (pEnd = strchr(pBegin, '|'))
1455 {
1456 _ustrTitle.assignUtf8(pBegin, pEnd);
1457
1458 // extract location
1459 pBegin = pEnd + 1;
1460 if (pEnd = strchr(pBegin, '|'))
1461 {
1462 // yet another separator found: we then have a config parameter
1463 _ustrLocation.assignUtf8(pBegin, pEnd);
1464
1465 // extract config (rest of pszCreateObject)
1466 pBegin = pEnd + 1;
1467 _ustrSetupString.assignUtf8(pBegin);
1468 }
1469 else
1470 // no separator after "location" found:
1471 // duplicate whole string
1472 _ustrLocation.assignUtf8(pBegin);
1473
1474 if (!_ustrLocation())
1475 throw BSConfigExcpt(WPOEXCPT_NOLOCATION, ustrCreateObject);
1476
1477 // check if the location is correctly in <> brackets
1478 // V0.9.15 (2001-08-26) [umoeller]
1479 PCSZ pcszLocation = _ustrLocation.GetBuffer();
1480 if ( (pcszLocation[0] == '<')
1481 && (pcszLocation[_ustrLocation.length() - 1] != '>')
1482 )
1483 throw BSConfigExcpt(WPOEXCPT_INVALIDLOCATIONSTRING, ustrCreateObject);
1484 }
1485 else
1486 throw BSConfigExcpt(WPOEXCPT_NOTITLE, ustrCreateObject);
1487 }
1488 else
1489 throw BSConfigExcpt(WPOEXCPT_NOCLASS, ustrCreateObject);
1490}
1491
1492/*
1493 *@@ DescribeType:
1494 * describes the current manipulator type to the GUI.
1495 *
1496 *@@added V0.9.9 (2001-03-27) [umoeller]
1497 */
1498
1499const char* BSCreateWPSObject::DescribeType()
1500{
1501 return ("WPS object");
1502}
1503
1504/*
1505 *@@ DescribeData:
1506 * describes the current manipulator data to the GUI.
1507 *
1508 *@@added V0.9.9 (2001-03-27) [umoeller]
1509 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1510 */
1511
1512ustring BSCreateWPSObject::DescribeData()
1513{
1514 ustring ustr = _ustrClassName;
1515 ustr.appendUtf8(" ");
1516 ustr += _ustrTitle;
1517 ustr.appendUtf8(" ");
1518 ustr += _ustrLocation;
1519 ustr.appendUtf8(" ");
1520 ustr += _ustrSetupString;
1521
1522 return (ustr);
1523}
1524
1525/*
1526 *@@ CreateObject:
1527 * this attempts to create the WPS object
1528 * with the instance data.
1529 *
1530 * Throws a BSConfigExcpt with WPOEXCPT_CREATE
1531 * if this fails.
1532 *
1533 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1534 */
1535
1536void BSCreateWPSObject::CreateObject(BSUniCodec &codecProcess, // in: codec for process codepage,
1537 BSWPSObjectsDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
1538 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1539{
1540 CONVERT(&codecProcess, ClassName); // creates local string strXXX, PCSZ pcszXXX
1541 CONVERT(&codecProcess, Title); // creates local string strXXX, PCSZ pcszXXX
1542 CONVERT(&codecProcess, SetupString); // creates local string strXXX, PCSZ pcszXXX
1543 CONVERT(&codecProcess, Location); // creates local string strXXX, PCSZ pcszXXX
1544
1545 // check if the target folder exists, this is the most common problem
1546 // if WinCreateObject fails
1547 // V0.9.19 (2002-06-15) [umoeller]
1548
1549 if (!WinQueryObject(pcszLocation))
1550 {
1551 if (pLogFile)
1552 pLogFile->Write("Error creating WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\": Invalid target folder",
1553 pcszTitle,
1554 pcszClassName,
1555 pcszLocation,
1556 pcszSetupString);
1557
1558 throw BSConfigExcpt(WPOEXCPT_CREATE_BADLOCATION, _ustrTitle);
1559 }
1560
1561 if (!(_hobj = WinCreateObject(pcszClassName,
1562 pcszTitle,
1563 pcszSetupString,
1564 pcszLocation,
1565 (_fReplace)
1566 ? CO_REPLACEIFEXISTS
1567 : CO_UPDATEIFEXISTS)))
1568 {
1569 if (pLogFile)
1570 pLogFile->Write("Error creating WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\"",
1571 pcszTitle,
1572 pcszClassName,
1573 pcszLocation,
1574 pcszSetupString);
1575
1576 throw BSConfigExcpt(WPOEXCPT_CREATE, _ustrTitle);
1577 }
1578
1579 // V1.0.5 (2005-02-17) [pr]
1580 // We now save the object synchronously to prevent objects getting lost if we
1581 // restart the WPS imminently due to a class registration for example. @@fixes 634.
1582 WinSaveObject (_hobj, FALSE);
1583 if (pLogFile)
1584 {
1585 pLogFile->Write("Created WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\"",
1586 pcszTitle,
1587 pcszClassName,
1588 pcszLocation,
1589 pcszSetupString);
1590 pLogFile->Write("HOBJECT is 0x%lX", _hobj);
1591 }
1592
1593 // store the object ID in the logger
1594 PCSZ pObjectID;
1595 if ( // do we have a setup string at all?
1596 (pObjectID = _ustrSetupString.GetBuffer())
1597 // does it contain an object ID?
1598 && (pObjectID = strhistr(pObjectID,
1599 "OBJECTID=<"))
1600 )
1601 {
1602 PCSZ pBegin = pObjectID + 9; // points to '<' now
1603 PCSZ pEnd;
1604 if (pEnd = strchr(pBegin, '>'))
1605 {
1606 ustring ustrObjectID;
1607 ustrObjectID.assignUtf8(pBegin, pEnd + 1);
1608 if (pLogger)
1609 pLogger->Append(ustrObjectID);
1610 }
1611 }
1612}
1613
1614/* ******************************************************************
1615 *
1616 * BSDeleteWPSObject class
1617 *
1618 ********************************************************************/
1619
1620/*
1621 *@@ BSDeleteWPSObject:
1622 * the constructor, which in this case takes a simple
1623 * PSZ object ID as input.
1624 */
1625
1626BSDeleteWPSObject::BSDeleteWPSObject(const ustring &ustrID2Delete)
1627 : BSConfigBase(CFGT_DELETEOBJECT, tBSDeleteWPSObject)
1628{
1629 _ustrObjectID = ustrID2Delete;
1630}
1631
1632/*
1633 *@@ DescribeType:
1634 * describes the current manipulator type to the GUI.
1635 *
1636 *@@added V0.9.2 (2000-02-19) [umoeller]
1637 */
1638
1639const char* BSDeleteWPSObject::DescribeType()
1640{
1641 return ("WPS object deletion");
1642}
1643
1644/*
1645 *@@ DescribeData:
1646 * describes the current manipulator data to the GUI.
1647 *
1648 *@@added V0.9.2 (2000-02-19) [umoeller]
1649 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1650 */
1651
1652ustring BSDeleteWPSObject::DescribeData()
1653{
1654 return (_ustrObjectID);
1655}
1656
1657/*
1658 *@@ Delete:
1659 * this attempts to delete the object.
1660 * Throws a BSConfigExcpt upon failure.
1661 *
1662 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1663 */
1664
1665int BSDeleteWPSObject::Delete(BSUniCodec &codecProcess,
1666 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1667 const
1668{
1669 int irc = 0;
1670
1671 CONVERT(&codecProcess, ObjectID); // creates local string strXXX, PCSZ pcszXXX
1672
1673 HOBJECT hobj;
1674 if (!(hobj = WinQueryObject(pcszObjectID)))
1675 {
1676 if (pLogFile)
1677 pLogFile->Write("Error deleting WPS object \"%s\"",
1678 pcszObjectID);
1679
1680 throw BSConfigExcpt(WPOEXCPT_DELETEOBJECT, 0);
1681 }
1682
1683 if (!WinDestroyObject(hobj))
1684 {
1685 if (pLogFile)
1686 pLogFile->Write("Error deleting WPS object \"%s\", HOBJECT was 0x%lX",
1687 pcszObjectID,
1688 hobj);
1689
1690 throw BSConfigExcpt(WPOEXCPT_DELETEOBJECT, 0);
1691 }
1692
1693 return (irc);
1694}
1695
1696/*
1697 *@@ AddToUndoList:
1698 * static helper method to create BSDeleteWPSObject
1699 * instances from the logger instance that was
1700 * previously used with BSRegisterClass::Register.
1701 *
1702 * The new BSDeleteWPSObject objects are appended to
1703 * the specified list.
1704 *
1705 * This returns the number of items created.
1706 */
1707
1708int BSDeleteWPSObject::AddToUndoList(list<BSConfigBase*> &List,
1709 BSWPSObjectsDoneLogger &logger)
1710{
1711 // the logger in this case has a simple list of PSZs with all
1712 // the object IDs that were created, each of which is terminated
1713 // with a null character
1714
1715 PSZ pszLogStart = logger._pabLogString,
1716 pszLogThis = pszLogStart;
1717 int iCount = 0;
1718
1719 while (pszLogThis < pszLogStart + logger._cbLogString)
1720 {
1721 ULONG cbLogThis = strlen(pszLogThis);
1722 ustring ustr;
1723 ustr.assignUtf8(pszLogThis);
1724 List.push_back(new BSDeleteWPSObject(ustr));
1725 pszLogThis += cbLogThis + 1; // go beyond null byte
1726 iCount++;
1727 }
1728
1729 return (iCount);
1730}
1731
1732/* ******************************************************************
1733 *
1734 * BSClearProfile class
1735 *
1736 ********************************************************************/
1737
1738/*
1739 *@@ DescribeType:
1740 * describes the current manipulator type to the GUI.
1741 *
1742 *@@added V0.9.2 (2000-02-19) [umoeller]
1743 */
1744
1745const char* BSProfileBase::DescribeType()
1746{
1747 return ("Profile data");
1748}
1749
1750/*
1751 *@@ DescribeData:
1752 * describes the current manipulator data to the GUI.
1753 *
1754 *@@added V0.9.2 (2000-02-19) [umoeller]
1755 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1756 */
1757
1758ustring BSProfileBase::DescribeData()
1759{
1760 return (DescribePrfKey());
1761}
1762
1763/*
1764 *@@ DescribePrfKey:
1765 * returns a descriptive string describing the
1766 * member fields, a la "USER\app\key".
1767 *
1768 *@@added V0.9.1 (2000-02-12) [umoeller]
1769 */
1770
1771ustring BSProfileBase::DescribePrfKey() const
1772{
1773 ustring str(_ustrProfile);
1774 if (_ustrApplication())
1775 {
1776 str.appendUtf8("\\");
1777 str += _ustrApplication;
1778
1779 if (_ustrKey())
1780 {
1781 str.appendUtf8("\\");
1782 str += _ustrKey;
1783 }
1784 }
1785
1786 return (str);
1787}
1788
1789/*
1790 *@@ DescribePrfKey:
1791 *
1792 *@@added V0.9.18 (2002-03-08) [umoeller]
1793 */
1794
1795string BSProfileBase::DescribePrfKey(BSUniCodec &codecProcess) const
1796{
1797 string str(&codecProcess, DescribePrfKey());
1798 return str;
1799}
1800
1801/*
1802 *@@ BSClearProfile:
1803 *
1804 * Syntax:
1805 *
1806 + CLEARPROFILE="profile\application[\key]"
1807 *
1808 *@@added V0.9.1 (2000-02-07) [umoeller]
1809 *@@changed V1.0.5 (2005-03-06) [pr]: Improved parsing of profiles with path names. @@fixes 633
1810 */
1811
1812BSClearProfile::BSClearProfile(const ustring &ustrClearProfile)
1813 : BSProfileBase(CFGT_CLEARPROFILE, tBSClearProfile)
1814{
1815 PCSZ pcszClearProfile = ustrClearProfile.GetBuffer();
1816
1817 // get profile
1818 PCSZ pFirstBackslash;
1819 if (pFirstBackslash = strchr(pcszClearProfile, '\\'))
1820 {
1821 // extract profile
1822 _ustrProfile.assignUtf8(pcszClearProfile, pFirstBackslash);
1823
1824 // V1.0.7 (2005-05-15) [pr]: Changed to case-insensitive compare as there are
1825 // a few broken packages out there
1826 if ( _ustrProfile.compareUtf8I("USER")
1827 && _ustrProfile.compareUtf8I("SYSTEM")
1828 )
1829 {
1830 while (pFirstBackslash)
1831 {
1832 ULONG cbProfile = pFirstBackslash - pcszClearProfile;
1833 if ( (cbProfile > 4)
1834 && (!strnicmp(pFirstBackslash - 4, ".INI", 4))
1835 )
1836 {
1837 _ustrProfile.assignUtf8(pcszClearProfile, pFirstBackslash);
1838 break;
1839 }
1840
1841 pFirstBackslash = strchr(pFirstBackslash + 1, '\\');
1842 }
1843 }
1844 }
1845
1846 if (pFirstBackslash)
1847 {
1848 // get application
1849 PCSZ pSecondBackslash;
1850 if (pSecondBackslash = strchr(pFirstBackslash + 2, '\\'))
1851 {
1852 // key specified:
1853 // extract application up to key
1854 _ustrApplication.assignUtf8(pFirstBackslash + 1, pSecondBackslash);
1855
1856 // extract key (all the rest)
1857 _ustrKey.assignUtf8(pSecondBackslash + 1);
1858 }
1859 else
1860 // key not specified:
1861 _ustrApplication.assignUtf8(pFirstBackslash + 1);
1862 }
1863
1864 if (!_ustrApplication())
1865 // any error:
1866 throw BSConfigExcpt(PRFEXCPT_SYNTAX, ustrClearProfile);
1867}
1868
1869/*
1870 *@@ Clear:
1871 * deletes the corresponding profile entry.
1872 *
1873 *@@added V0.9.5 (2000-08-26) [umoeller]
1874 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1875 */
1876
1877int BSClearProfile::Clear(BSUniCodec &codecProcess, // in: codec for process codepage,
1878 HAB hab,
1879 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1880 const
1881{
1882 BOOL fOK = FALSE;
1883 HINI hini = NULLHANDLE,
1884 hini2Close = NULLHANDLE;
1885
1886 if (!_ustrProfile.compareUtf8("USER"))
1887 hini = HINI_USER;
1888 else if (!_ustrProfile.compareUtf8("SYSTEM"))
1889 hini = HINI_SYSTEM;
1890 else
1891 {
1892 CONVERT(&codecProcess, Profile);
1893 hini = PrfOpenProfile(hab,
1894 pcszProfile);
1895 hini2Close = hini;
1896 }
1897
1898 if (hini)
1899 {
1900 CONVERT(&codecProcess, Application);
1901 CONVERT(&codecProcess, Key);
1902
1903 ULONG cb = 0;
1904 // does key exist?
1905 if (PrfQueryProfileSize(hini,
1906 pcszApplication,
1907 pcszKey, // can be NULL
1908 &cb))
1909 {
1910 // key exists:
1911 if (PrfWriteProfileString(hini,
1912 pcszApplication,
1913 pcszKey, // can be NULL
1914 NULL))
1915 fOK = TRUE;
1916 }
1917 else
1918 // key does not exist:
1919 fOK = TRUE;
1920 }
1921
1922 if (!fOK)
1923 {
1924 string strClear = DescribePrfKey(codecProcess);
1925 if (pLogFile)
1926 pLogFile->Write("Error deleting profile key \"%s\"",
1927 strClear.c_str());
1928
1929 // error:
1930 throw BSConfigExcpt(PRFEXCPT_PRFERROR, DescribePrfKey());
1931 }
1932
1933 if (pLogFile)
1934 {
1935 string strClear = DescribePrfKey(codecProcess);
1936 pLogFile->Write("Deleted profile key \"%s\"",
1937 strClear.c_str());
1938 }
1939
1940 return (1);
1941}
1942
1943/*
1944 *@@ AddToUndoList:
1945 * static helper method to create BSClearProfile
1946 * instances from the specified logger instance.
1947 * Note that this class method will be used both
1948 * for "CLEARPROFILE" tags specified in the script
1949 * as well as "WRITEPROFILE" tags which were actually
1950 * executed (written to a profile).
1951 *
1952 * The new BSClearProfile objects are appended to
1953 * the specified list.
1954 *
1955 * This returns the number of items created.
1956 */
1957
1958int BSClearProfile::AddToUndoList(list<BSConfigBase*> &List,
1959 BSClearPrfAttrsLogger &logger)
1960{
1961 // the logger in this case has a simple list of PSZs with all
1962 // the profile keys that were created, each of which is terminated
1963 // with a null character
1964
1965 PSZ pszLogStart = logger._pabLogString,
1966 pszLogThis = pszLogStart;
1967 int iCount = 0;
1968
1969 while (pszLogThis < pszLogStart + logger._cbLogString)
1970 {
1971 ULONG cbLogThis = strlen(pszLogThis);
1972 ustring ustr;
1973 ustr.assignUtf8(pszLogThis);
1974 List.push_back(new BSClearProfile(ustr));
1975 pszLogThis += cbLogThis + 1; // go beyond null byte
1976 iCount++;
1977 }
1978
1979 return (iCount);
1980}
1981
1982/* ******************************************************************
1983 *
1984 * BSWriteProfile class
1985 *
1986 ********************************************************************/
1987
1988/*
1989 *@@ BSWriteProfile:
1990 *
1991 * Syntax:
1992 *
1993 + WRITEPROFILE="profile\application\key|string"
1994 *
1995 *@@added V0.9.1 (2000-02-07) [umoeller]
1996 *@@changed V0.9.19 (2002-05-07) [umoeller]: added missing class init, now writeprofiles work again
1997 *@@changed V1.0.5 (2005-03-06) [pr]: Improved parsing of profiles with path names. @@fixes 633
1998 */
1999
2000BSWriteProfile::BSWriteProfile(const ustring &ustrWriteProfile)
2001 : BSProfileBase(CFGT_WRITEPROFILE, tBSWriteProfile)
2002{
2003 PCSZ pcszWriteProfile = ustrWriteProfile.GetBuffer();
2004
2005 // override class, this was still BSClearProfile due
2006 // to the constructor; this is also why writeprofiles
2007 // never worked V0.9.19 (2002-05-07) [umoeller]
2008 _Class = tBSWriteProfile;
2009
2010 PCSZ pSlash;
2011 if (pSlash = strchr(pcszWriteProfile, '|'))
2012 {
2013 // copy write data (after '|')
2014 _ustrWriteString.assignUtf8(pSlash + 1);
2015
2016 // get profile
2017 PCSZ pFirstBackslash;
2018 if (pFirstBackslash = strchr(pcszWriteProfile, '\\'))
2019 {
2020 // extract profile
2021 _ustrProfile.assignUtf8(pcszWriteProfile, pFirstBackslash);
2022
2023 if ( _ustrProfile.compareUtf8("USER")
2024 && _ustrProfile.compareUtf8("SYSTEM")
2025 )
2026 {
2027 while (pFirstBackslash)
2028 {
2029 ULONG cbProfile = pFirstBackslash - pcszWriteProfile;
2030 if ( (cbProfile > 4)
2031 && (!strnicmp(pFirstBackslash - 4, ".INI", 4))
2032 && (pFirstBackslash < pSlash)
2033 )
2034 {
2035 _ustrProfile.assignUtf8(pcszWriteProfile, pFirstBackslash);
2036 break;
2037 }
2038
2039 pFirstBackslash = strchr(pFirstBackslash + 1, '\\');
2040 }
2041 }
2042 }
2043
2044 if (pFirstBackslash)
2045 {
2046 // get application
2047 PCSZ pSecondBackslash;
2048 if (pSecondBackslash = strchr(pFirstBackslash + 2, '\\'))
2049 {
2050 // extract application
2051 _ustrApplication.assignUtf8(pFirstBackslash + 1, pSecondBackslash);
2052
2053 // extract key (up to '|')
2054 _ustrKey.assignUtf8(pSecondBackslash + 1, pSlash);
2055 }
2056 }
2057 }
2058
2059 if (!_ustrKey())
2060 // any error:
2061 throw BSConfigExcpt(PRFEXCPT_SYNTAX, ustrWriteProfile);
2062}
2063
2064/*
2065 *@@ Write:
2066 * this actually writes data to a profile, all
2067 * as specified by the member variables.
2068 *
2069 * Note that this stores the "done" stuff in
2070 * a BSClearPrfAttrsLogger for undoing later.
2071 *
2072 * Throws:
2073 * -- BSConfigExcpt.
2074 *
2075 *@@added V0.9.1 (2000-02-07) [umoeller]
2076 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
2077 */
2078
2079int BSWriteProfile::Write(BSUniCodec &codecProcess, // in: codec for process codepage,
2080 HAB hab, // in: anchor block (for PrfOpenProfile)
2081 BSClearPrfAttrsLogger *pLogger,
2082 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
2083 const
2084{
2085 BOOL fOK = FALSE;
2086 HINI hini = NULLHANDLE,
2087 hini2Close = NULLHANDLE;
2088
2089 if (!_ustrProfile.compareUtf8("USER"))
2090 hini = HINI_USER;
2091 else if (!_ustrProfile.compareUtf8("SYSTEM"))
2092 hini = HINI_SYSTEM;
2093 else
2094 {
2095 CONVERT(&codecProcess, Profile);
2096 if (!(hini = PrfOpenProfile(hab,
2097 pcszProfile)))
2098 throw BSConfigExcpt(PRFEXCPT_PRFOPENPROFILE, _ustrProfile);
2099
2100 hini2Close = hini;
2101 }
2102
2103 if (hini)
2104 {
2105 CONVERT(&codecProcess, Application);
2106 CONVERT(&codecProcess, Key);
2107 CONVERT(&codecProcess, WriteString);
2108 if (PrfWriteProfileString(hini,
2109 pcszApplication,
2110 pcszKey,
2111 pcszWriteString))
2112 {
2113 fOK = TRUE;
2114 }
2115 }
2116
2117 // recompose string for BSClearProfile
2118 ustring ustrClear = DescribePrfKey();
2119 string strClear = DescribePrfKey(codecProcess);
2120
2121 if (fOK)
2122 {
2123 if (pLogFile)
2124 pLogFile->Write("Wrote profile key \"%s\"",
2125 strClear.c_str());
2126
2127 if (pLogger)
2128 pLogger->Append(ustrClear);
2129 }
2130 else
2131 {
2132 // error:
2133 if (pLogFile)
2134 pLogFile->Write("Error writing profile key \"%s\"",
2135 strClear.c_str());
2136
2137 throw BSConfigExcpt(PRFEXCPT_PRFERROR, DescribePrfKey());
2138 }
2139
2140 return 1;
2141}
2142
2143/* ******************************************************************
2144 *
2145 * BSExecute class
2146 *
2147 ********************************************************************/
2148
2149/*
2150 *@@ BSExecute:
2151 * this constructor takes an EXECUTE attribute (of the PCK tag)
2152 * as input and sets up the instance data accordingly.
2153 *
2154 * Syntax:
2155 *
2156 + EXECUTE="[ context ] execfile params"
2157 *
2158 * Throws:
2159 * -- BSConfigExcpt.
2160 *
2161 *@@added V0.9.1 (2000-02-07) [umoeller]
2162 *@@changed V0.9.3 (2000-04-08) [umoeller]: "|" was a requirement, contradicting the docs; changed. Thanks, Cornelis Bockemhl.
2163 *@@changed V0.9.4 (2000-07-10) [umoeller]: _ulExecType wasn't always initialized; thanks Yuri Dario
2164 *@@changed V0.9.4 (2000-07-26) [umoeller]: now ORing the flags
2165 *@@changed V0.9.9 (2001-03-27) [umoeller]: fixed EXECUTE parameters
2166 */
2167
2168BSExecute::BSExecute(const ustring &ustrExecute,
2169 BSClassID &Class)
2170 : BSConfigBase(CFGT_EXECUTE, Class)
2171{
2172 BOOL fContextFound = FALSE,
2173 fContinue = TRUE;
2174 PCSZ pcszExecute = ustrExecute.GetBuffer();
2175 PCSZ pSearch = (PSZ)pcszExecute;
2176
2177 _ulExecType = 0;
2178 _arc = 0; // NO_ERROR
2179
2180 while (fContinue)
2181 {
2182 // skip leading spaces
2183 while ( (*pSearch)
2184 && (*pSearch == ' ')
2185 )
2186 pSearch++;
2187
2188 if (strncmp(pSearch, "CONFIGSYS", 9) == 0)
2189 {
2190 _ulExecType |= CFGT_CFGSYS;
2191 fContextFound = TRUE;
2192 pSearch += 9; // strlen("CONFIGSYS");
2193 }
2194 else if (strncmp(pSearch, "REGISTERCLASS", 13) == 0)
2195 {
2196 _ulExecType |= CFGT_REGISTERCLASS;
2197 fContextFound = TRUE;
2198 pSearch += 13; // strlen("REGISTERCLASS");
2199 }
2200 else if (strncmp(pSearch, "CREATEOBJECT", 12) == 0)
2201 {
2202 _ulExecType |= CFGT_CREATEOBJECT;
2203 fContextFound = TRUE;
2204 pSearch += 12; // strlen("CREATEOBJECT");
2205 }
2206 else
2207 // other: stop looping
2208 fContinue = FALSE;
2209 } // end while (fContinue)
2210
2211 if (!(*pSearch))
2212 throw BSConfigExcpt(EXEEXCPT_SYNTAX, ustrExecute);
2213
2214 // pSearch now points to the first non-space
2215 // character which does not introduces a keyword;
2216 // check if this is a "|" separator
2217
2218 if (*pSearch == '|')
2219 // skip '|'
2220 pSearch++;
2221
2222 // skip following spaces
2223 while ( (*pSearch)
2224 && (*pSearch == ' ')
2225 )
2226 pSearch++;
2227
2228 // NOW we finally point to the executable
2229
2230 if (!(*pSearch))
2231 throw BSConfigExcpt(EXEEXCPT_SYNTAX, ustrExecute);
2232
2233 // separate executable and parameters:
2234 // This can be separated by another '|',
2235 // or a space.
2236
2237 // NOTE: The '|' separator is used by the "resolved"
2238 // logger, from which BSDeExecute instances are
2239 // created on de-install. But the documentation states
2240 // spaces should be used... as long as a user doesn't
2241 // use spaces in the (unresolved) filename, we're fine.
2242 // For example we get:
2243 // 1) on install: $(1)\install.cmd PARAMETER
2244 // works nicely, and $(1) may contain spaces.
2245 // 2) Logger stores C:\PATH1 WITH SPACES\install.cmd|PARAMETER
2246 // in database.
2247 // 3) on deinstall, BSDeExecutes get created, and
2248 // we now have nice separation and get PARAMETER
2249 // properly separated.
2250 PCSZ p;
2251 if (!(p = strchr(pSearch, '|')))
2252 p = strchr(pSearch, ' ');
2253 if (p)
2254 {
2255 const char *pSep = p++; // V1.0.5 (2005-01-20) [pr]: @@fixes 624
2256 // we have a space --> parameters:
2257 while ( (*p)
2258 && (*p == ' ')
2259 )
2260 p++;
2261
2262 if (*p)
2263 {
2264 _ustrParams.assignUtf8(p);
2265 _ustrExecutable.assignUtf8(pSearch, pSep);
2266 }
2267 else
2268 _ustrExecutable.assignUtf8(pSearch);
2269 }
2270 else
2271 _ustrExecutable.assignUtf8(pSearch);
2272}
2273
2274/*
2275 *@@ DescribeType:
2276 * describes the current manipulator type to the GUI.
2277 *
2278 *@@added V0.9.9 (2001-03-27) [umoeller]
2279 */
2280
2281const char* BSExecute::DescribeType()
2282{
2283 return ("Execute program");
2284}
2285
2286/*
2287 *@@ DescribeData:
2288 * describes the current manipulator data to the GUI.
2289 *
2290 *@@added V0.9.9 (2001-03-27) [umoeller]
2291 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
2292 */
2293
2294ustring BSExecute::DescribeData()
2295{
2296 ustring ustr;
2297 ustr._printf("\"%s\"", _ustrExecutable.GetBuffer());
2298
2299 if (_ustrParams())
2300 {
2301 ustr.appendUtf8(" \"");
2302 ustr += _ustrParams;
2303 ustr.appendUtf8("\"");
2304 }
2305
2306 if (_ulExecType == 0)
2307 ustr.appendUtf8(" (no flags)");
2308 else
2309 {
2310 if (_ulExecType & CFGT_CFGSYS)
2311 ustr.appendUtf8(" CONFIGSYS");
2312 if (_ulExecType & CFGT_REGISTERCLASS)
2313 ustr.appendUtf8(" REGISTERCLASS");
2314 if (_ulExecType & CFGT_CREATEOBJECT)
2315 ustr.appendUtf8(" CREATEOBJECT");
2316 }
2317
2318 return (ustr);
2319}
2320
2321/*
2322 *@@ Execute:
2323 * executes the member program. This does not return
2324 * until the program terminates. As a result, do not
2325 * call this on a PM thread, because this gets blocked.
2326 *
2327 * Throws:
2328 * -- BSConfigExcpt.
2329 *
2330 *@@added V0.9.1 (2000-02-07) [umoeller]
2331 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
2332 *@@changed V1.0.5 (2005-01-25) [pr]: Change directory to that of executable
2333 */
2334
2335int BSExecute::Execute(BSUniCodec &codecProcess, // in: codec for process codepage,
2336 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
2337{
2338 string strParams = "/c ";
2339 strParams.appendUtf8(&codecProcess, _ustrExecutable);
2340 if (_ustrParams())
2341 {
2342 strParams += " ";
2343 strParams.appendUtf8(&codecProcess, _ustrParams);
2344 }
2345
2346 // V1.0.5 (2005-01-26) [pr]: Change directory to that of executable. @@fixes 626.
2347 // We remove any leading quotes and just leave the directory name, excluding a
2348 // trailing slash, unless it is a root directory.
2349 string strDir;
2350 strDir.assignUtf8(&codecProcess, _ustrExecutable);
2351 strDir = strDir.substr(strDir.find_first_not_of("\"'"));
2352 size_type pos = strDir.rfind('\\', 0);
2353 if (pos != string::npos)
2354 {
2355 strDir.erase(pos);
2356 if (strDir.size() == 2 && strDir[1] == ':')
2357 strDir += '\\';
2358
2359 doshSetCurrentDir(strDir.c_str());
2360 }
2361
2362 ULONG sid = 0;
2363 PID pid = 0;
2364 if (_arc = doshQuickStartSession("cmd.exe",
2365 (PSZ)strParams.c_str(),
2366 SSF_TYPE_DEFAULT, // session type
2367 FALSE, // foreground
2368 0, // auto-close, visible
2369 TRUE, // wait
2370 &sid,
2371 &pid,
2372 NULL))
2373 {
2374 if (pLogFile)
2375 pLogFile->Write("Error %d executing \"CMD.EXE %s\"",
2376 _arc,
2377 strParams.c_str());
2378
2379 throw BSConfigExcpt(EXEEXCPT_DOSERROR, _arc);
2380 }
2381
2382 if (pLogFile)
2383 pLogFile->Write("Executed \"CMD.EXE %s\"",
2384 strParams.c_str());
2385
2386 return (0);
2387}
2388
2389/* ******************************************************************
2390 *
2391 * BSDeExecute class
2392 *
2393 ********************************************************************/
2394
2395/*
2396 *@@ BSDeExecute:
2397 * constructor.
2398 *
2399 *@@added V0.9.16 (2001-12-08) [umoeller]
2400 */
2401
2402BSDeExecute::BSDeExecute(const ustring &ustrDeExecute)
2403 : BSExecute(ustrDeExecute, tBSDeExecute)
2404{
2405};
2406
2407/*
2408 *@@ DescribeType:
2409 * describes the current manipulator type to the GUI.
2410 *
2411 *@@added V0.9.2 (2000-02-19) [umoeller]
2412 */
2413
2414const char* BSDeExecute::DescribeType()
2415{
2416 return ("External program for deinstall");
2417}
2418
2419/*
2420 *@@ AddToUndoList:
2421 * static helper method to create BSDeExecute instances from
2422 * the specified logger instance.
2423 *
2424 * The new BSKillProcess objects are appended to
2425 * the specified list.
2426 *
2427 * This returns the number of items created.
2428 *
2429 * This isn't really an "Undo" method like the other
2430 * static AddToUndoList methods (for the other classes),
2431 * but has been named like this for conformity. This
2432 * is during package de-install to create the same
2433 * BSDeExecute list which was initially created from
2434 * the script so that processes can be killed during
2435 * de-install as well.
2436 *
2437 *@@added V0.9.9 (2001-03-27) [umoeller]
2438 */
2439
2440int BSDeExecute::AddToUndoList(list <BSConfigBase*> &List,
2441 BSDeExecuteResolvedLogger &logger)
2442{
2443 PSZ pszLogStart = logger._pabLogString,
2444 pszLogThis = pszLogStart;
2445 int iCount = 0;
2446
2447 while (pszLogThis < pszLogStart + logger._cbLogString)
2448 {
2449 ULONG cbLogThis = strlen(pszLogThis);
2450 ustring ustr;
2451 ustr.assignUtf8(pszLogThis);
2452 List.push_back(new BSDeExecute(ustr));
2453 pszLogThis += cbLogThis + 1; // go beyond null byte
2454 iCount++;
2455 }
2456
2457 return (iCount);
2458}
2459
2460/* ******************************************************************
2461 *
2462 * BSKillProcess class
2463 *
2464 ********************************************************************/
2465
2466/*
2467 *@@ BSKillProcess:
2468 *
2469 * Syntax:
2470 *
2471 + KILLPROCESS="filename"
2472 *
2473 * Throws:
2474 * -- BSConfigExcpt.
2475 *
2476 *@@added V0.9.1 (2000-02-12) [umoeller]
2477 */
2478
2479BSKillProcess::BSKillProcess(const ustring &ustrKillProcess)
2480 : BSConfigBase(CFGT_KILLPROCESS, tBSKillProcess)
2481{
2482 if (!ustrKillProcess())
2483 throw BSConfigExcpt(KILLEXCPT_SYNTAX, ustrKillProcess);
2484
2485 _ustrKillProcess = ustrKillProcess;
2486}
2487
2488/*
2489 *@@ DescribeType:
2490 * describes the current manipulator type to the GUI.
2491 *
2492 *@@added V0.9.4 (2000-07-01) [umoeller]
2493 */
2494
2495const char* BSKillProcess::DescribeType()
2496{
2497 return ("Kill process");
2498}
2499
2500/*
2501 *@@ DescribeData:
2502 * describes the current manipulator data to the GUI.
2503 *
2504 *@@added V0.9.4 (2000-07-01) [umoeller]
2505 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
2506 */
2507
2508ustring BSKillProcess::DescribeData()
2509{
2510 return _ustrKillProcess;
2511}
2512
2513/*
2514 *@@ AddToUndoList:
2515 * static helper method to create BSKillProcess
2516 * instances from the specified logger instance.
2517 *
2518 * The new BSKillProcess objects are appended to
2519 * the specified list.
2520 *
2521 * This returns the number of items created.
2522 *
2523 * This isn't really an "Undo" method like the other
2524 * static AddToUndoList methods (for the other classes),
2525 * but has been named like this for conformity. This
2526 * is during package de-install to create the same
2527 * BSKillProcess list which was initially created from
2528 * the script so that processes can be killed during
2529 * de-install as well.
2530 *
2531 *@@added V0.9.4 (2000-07-01) [umoeller]
2532 */
2533
2534int BSKillProcess::AddToUndoList(list<BSConfigBase*> &List,
2535 BSKillProcessAttrsLogger &logger)
2536{
2537 // the logger in this case has a simple list of PSZs with all
2538 // the executable names that were created, each of which is
2539 // terminated with a null character
2540
2541 PSZ pszLogStart = logger._pabLogString,
2542 pszLogThis = pszLogStart;
2543 int iCount = 0;
2544
2545 while (pszLogThis < pszLogStart + logger._cbLogString)
2546 {
2547 ULONG cbLogThis = strlen(pszLogThis);
2548 ustring ustr;
2549 ustr.assignUtf8(pszLogThis);
2550 List.push_back(new BSKillProcess(ustr));
2551 pszLogThis += cbLogThis + 1; // go beyond null byte
2552 iCount++;
2553 }
2554
2555 return (iCount);
2556}
2557
2558
Note: See TracBrowser for help on using the repository browser.