source: trunk/src/cppbase/bs_config.cpp

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

Add missing xprf() functions. Fix broken ones also.

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