NEWPKG.CPP

//************************************************************************** 
// Copyright (C) 1995 by Microsoft Corporation.
//
// File: newpkg.cpp
//
// DESCRIPTION:
//
// This program illustrates how to use the SMS SDK to view, create, and
// delete packages. It can be used to create sharing and workstation
// packages but not inventory packages. Also the packages created with
// only a single sub-folder. Thus the packages it creates can not be for
// both sharing and workstations.
//
//
// PROGRAM FLOW:
//
// After logging on to a datasource, a package container is created and
// populated. The program then enters a loop asking whether the user
// wants to view the next package folder, delete the currently viewed
// folder, or create a new folder.
//
// Author: Larry A. French
//
//==========================================================================
// The following API calls are used in this program.
//
// SmsDataSourceConnect
// SmsDataSourceDisconnect
// SmsOpenContainer
// SmsCloseContainer
// SmsCreateFolder
// SmsPopulate
// SmsGetNextFolder
// SmsDescribeFolder
// SmsGetFolderID
// SmsGetFolderType
// SmsGetFolderCount
// SmsLinkFolder
// SmsUnlinkFolder
// SmsCommitFolder
// SmsRewind
// SmsCloseFolder
// SmsGetScalarCount
// SmsSetScalar
// SmsGetNextScalar
//
//**************************************************************************


// ====================================================================
// Includes.
// ====================================================================
#include <afx.h>
#include <stdlib.h> // for itoa
#include <smsapi.h> // Header for the APIs.
#include <time.h> // for time functions.

// Include the GetStatusName function.
// -------------------------------------
#include "..\common\status.inc"


// ====================================================================
//
// Defines.
//
// ====================================================================

#define CCH_MAXSTRING 256
#define MAX_CREATE 100

#define PACKAGE_PERMISSIONS (PACKAGE_USER_READ | PACKAGE_USER_WRITE | PACKAGE_GUEST_READ)



// ====================================================================
//
// Prototypes.
//
// ====================================================================

void DisplayScalars( HANDLE hFolder );
void ViewFolder( HANDLE hFolder );
HANDLE CreatePackageFolder( HANDLE hFolderParent );
time_t ReadTime();
BOOL DidRequestHelp(int argc, char** argv);
void DisplayHelp();
void DisplayGreeting();
BOOL UserSaysYes(const char* pszPrompt);
HANDLE ConnectToDatasource();
void DisplaySmsError(const char* pszMessage, SMS_STATUS stat);
const char* GetStatusName(SMS_STATUS stat);
void InputString(const char* pszMessage, char* pszResult);




// ====================================================================
//
// The work starts here.
//
// ====================================================================
void main(int argc, char** argv)
{
// Check to see if this is a request to display the help
// screen. If so, display it. Otherwise, display a greeting
// banner.
//=========================================================
if (DidRequestHelp(argc, argv)) {
DisplayHelp();
return;
}
else {
DisplayGreeting();
}


SMS_STATUS stat;
HANDLE hConnect;
HANDLE hContainerPkg;
DWORD numFolders;
DWORD numFoldersMax;
DWORD dwFolder;
DWORD dwIndex;


// Connect to the data source. If the connect fails, give up.
// Note that a status message will be displayed by ConnectToDatasource.
//=====================================================================
hConnect = ConnectToDatasource();
if (hConnect == NULL) {
return;
}

// Open package container.
// ==============================================================
stat = SmsOpenContainer( C_PACKAGE, hConnect, &hContainerPkg );
if (stat != SMS_OK) {
printf("SmsOpenContainer failed: %d\n", stat);
SmsDataSourceDisconnect( hConnect );
return;
}

// Any filters would be set here.


// Select all folders matching our filters.
// ========================================
stat = SmsPopulate( hContainerPkg, POP_SYNC, NULL);
if (!(stat == SMS_OK || stat==SMS_EMPTY)) {
printf("Bad return from SmsPopulate: %d\n", stat);
SmsCloseContainer( hContainerPkg );
SmsDataSourceDisconnect( hConnect );
return;
}


stat = SmsGetFolderCount( hContainerPkg, F_ANY, &numFolders);
if (stat != SMS_OK) {
DisplaySmsError("SmsGetFolderCount failed on package container", stat);
return;
}

printf("========== Container has %d folders =========\n\n", numFolders );


// Allocate enough space to hold handles for all of the folders currently
// in the container, plus more than enough space to hold all of the folders
// that we will create.
//=========================================================================
numFoldersMax = numFolders + MAX_CREATE;

HANDLE *phFolders = (HANDLE *)malloc(numFoldersMax * sizeof(HANDLE));
HANDLE hFolder;

// Open all top-level folders.
// ---------------------------
for (dwFolder = 0; dwFolder < numFolders; dwFolder++) {
stat = SmsGetNextFolder( hContainerPkg, F_ANY, &hFolder );
if (stat != SMS_OK) {
printf("Error in retrieving a folder: %d\n", stat);
break;
}

phFolders[dwFolder] = hFolder;
}


// Now we enter a loop asking the user whether they want to
// view the next folder, Delete the folder just displayed,
// or create a new folder.
// =========================================================
BOOL bDoQuit = FALSE;
char szReply[CCH_MAXSTRING];
dwFolder = 0;

while (!bDoQuit) {

printf("\n\n");
printf("*******************************************\n");
printf("* Enter a command: *\n");
printf("* N View next folder. *\n");
printf("* P View previous folder. *\n");
printf("* V View current folder. *\n");
printf("* D Delete current folder. *\n");
printf("* C Create new folder. *\n");
printf("* X Exit. *\n");
printf("*******************************************\n");
printf("\n");

InputString("[NPVDCX]", szReply);

switch (szReply[0]) {
case 0:
case 'N': case 'n':

// Fall through to the "View" command
// =========== View next folder ====================
if ((dwFolder + 1) < numFolders) {
dwFolder++;
ViewFolder( phFolders[dwFolder] );
} else
printf("At end of folder list\n");
break;

case 'P': case 'p':
if (dwFolder > 0) {
--dwFolder;
ViewFolder(phFolders[dwFolder]);
} else {
printf("At first folder\n");
}
break;

case 'V': case 'v':
if (dwFolder >= 0 && dwFolder < numFolders) {
ViewFolder( phFolders[dwFolder]);
} else {
printf("View: No such folder: %d\n", dwFolder);
}
break;

case 'D': case 'd':
// =========== Delete current folder ===============

// Check we have a folder to delete.
if (dwFolder >= numFolders || dwFolder < 0) {
printf("Delete: No such folder: %d\n", dwFolder);
break;
}

hFolder = phFolders[dwFolder];

if (!UserSaysYes("Are you sure you want to delete this folder")) {
printf("Delete cancelled\n");
break;
}

stat = SmsUnlinkFolder( hFolder );
if (stat != SMS_OK) {
DisplaySmsError("Delete: UnlinkFolder failed", stat);
break;
}
stat = SmsCommitFolder( hFolder );
if (stat != SMS_OK) {
DisplaySmsError("Delete: commit folder failed", stat);
break;
}

// Close the folder so that its memory will be deallocated
// when all other references to it go away. Note that the
// container retains a reference to its folder, so the memory
// will not actually be deallocated until the container is
// also closed.
//==========================================================
stat = SmsCloseFolder(hFolder);
if (stat != SMS_OK) {
DisplaySmsError("Delete: close folder failed", stat);
break;
}

// Remove the folder's handle from the handle table.
//==================================================
for(dwIndex = dwFolder; dwIndex < (numFolders - 1); ++dwIndex) {
phFolders[dwIndex] = phFolders[dwIndex+1];
}

// Adjust the folder index and folder count.
// since there is now one less folder in the table.
//=================================================
--numFolders;
if ((dwFolder > 0) && (dwFolder >= numFolders)) {
--dwFolder;
}
printf("Folder deleted\n");
break;

case 'C': case 'c':
// =========== Create new folder ===================

// Check to see if the folder handle array is already
// full. If so, then display an error message and
// begin a new command.
//===================================================
if (numFolders >= numFoldersMax) {
printf("Can't create a new folder because the folder\n");
printf("handle array is full.\n");
printf("\n");
break;
}

HANDLE hFolderPkg;
hFolderPkg = CreatePackageFolder(hContainerPkg);
if (hFolderPkg != NULL) {
dwFolder = numFolders;
phFolders[numFolders++] = hFolderPkg;
}
break;

case 'X': case 'x':
// Terminate.
bDoQuit = TRUE;
break;

default:
// print the message again.
printf("Actions are: N(ext folder), D(elete folder), C(reate folder)\n");
printf("Type x to exit\n");
break;
}
}

// Close all of the package folders so that their memory will
// be deallocated (when the container is closed).
//===========================================================
for (dwFolder=0; dwFolder < numFolders; ++dwFolder) {
stat = SmsCloseFolder(phFolders[dwFolder]);
if (stat != SMS_OK) {
DisplaySmsError("Failed to close a package folder", stat);
}
}


// Close the container.
//=====================
stat = SmsCloseContainer( hContainerPkg );
if (stat != SMS_OK) {
DisplaySmsError("Failed to close the package container", stat);
}

// Disconnect from the datasource.
//================================
stat = SmsDataSourceDisconnect( hConnect );
if (stat != SMS_OK) {
DisplaySmsError("Failed to disconnecct from the datasource", stat);
}

// Deallocate memory used for folder handles.
//===========================================
free( phFolders );

} /* main */






//***************************************************************************
// ReadTime
//
// Ask the user to enter a time string and convert it to a time_t value.
//
// Input: None.
//
// Returns:
// time_t The time value the user entered.
//
//
//***************************************************************************
time_t ReadTime()
{
char szTime[CCH_MAXSTRING];
InputString("Enter time in the form mm/dd/yy hh:mm ", szTime);


int mon, day, year, hour, min;
time_t today;
time( &today );

// Get the month (1..12)
mon = (szTime[0] - '0') * 10 + (szTime[1]) - '0';
mon--;
if (mon < 0 || mon > 11) {
printf("Month wrong (valid 01-12)\n");
return(today);
}

// Day (1..31)
day = (szTime[3] - '0') * 10 + (szTime[4] - '0');
if (day < 1 || day > 31) {
printf("Day wrong (Valid 01-07)\n");
return(today);
}

// Year
year = (szTime[6] - '0') * 10 + (szTime[7] - '0');
if (year < 90 || year > 99) {
printf("Year wrong (Valid 90-99)\n");
return(today);
}

// Hour (0..23)
hour = (szTime[9] - '0') * 10 + (szTime[10] - '0');
if (hour < 0 || hour > 23) {
printf("Hour wrong (Valid 00-23)\n");
return(today);
}

// Minute (0..59)
min = (szTime[12] - '0') * 10 + (szTime[13] - '0');
if (min < 0 || min > 59) {
printf("Minute wrong (Valid 00-59)\n");
return(today);
}

// Format the time, we want a time_t.
struct tm theTime;
theTime.tm_mon = mon;
theTime.tm_mday = day;
theTime.tm_year = year;
theTime.tm_hour = hour;
theTime.tm_min = min;
theTime.tm_sec = 0;
theTime.tm_isdst = -1;

time_t time = mktime( &theTime );
return(time);
}




//**************************************************************************
// SetScalarString
//
// This function sets the value specified scalar to the given string
// value.
//
// Parameters:
// HANDLE hFolder
// The handle of the folder containing the scalar to modify.
// char* pszName
// The name of the scalar.
// char* pszValue
// The string that will be assigned to the scalar's value.
//
// Returns:
// SMS_STATUS
// The SMS status code.
//
// Note that the scalar specified must be of type SCALAR_STRING.
//***************************************************************************
SMS_STATUS SetScalarString(HANDLE hFolder, char* pszName, char* pszValue)
{
SCALAR sc;
sc.pszName = pszName;
sc.scType = SCALAR_STRING;
sc.pszValue = pszValue;

SMS_STATUS stat;
stat = SmsSetScalar(hFolder, &sc);
return( stat );
}




//**************************************************************************
// SetScalarDword
//
// This function sets the value of the specified scalar to
// the given DWORD value.
//
// Parameters:
// HANDLE hFolder
// The handle of the folder containing the scalar to modify.
// char* pszName
// The name of the scalar.
// DWORD dwValue
// The DWORD value to set the scalar to.
//
// Returns:
// SMS_STATUS
// The SMS status code.
//
// Note that the scalar specified must be of type SCALAR_INT.
//***************************************************************************
SMS_STATUS SetScalarDword(HANDLE hFolder, char* pszName, DWORD dwValue)
{
SCALAR sc;
sc.pszName = pszName;
sc.scType = SCALAR_INT;
sc.dwValue = dwValue;


SMS_STATUS stat;
stat = SmsSetScalar(hFolder, &sc);
return( stat );
}




//**************************************************************************
// GetPlatformSelection
//
// Prompt the user to select a one or more platforms. The platforms are
// selected by entering a comma separated list of platform indexes. These
// platform indexes are converted to the platforms flags value for the SDK.
//
// Parameters: None.
//
// Returns:
// The SMS SDK platform flags value.
//***************************************************************************
DWORD GetPlatformSelection()
{
printf("\n\n");
printf("**********************************************\n");
printf("* Select a platform from the following list. *\n");
printf("**********************************************\n");
printf(" 1) MS-DOS \n");
printf(" 2) Windows 3.1\n");
printf(" 3) Windows 95\n");
printf(" 4) Windows NT (X86)\n");
printf(" 5) Windows NT (Mips)\n");
printf(" 6) Windows NT (Alpha)\n");
printf(" 7) Macintosh\n");
printf("\n");

DWORD dwPlatforms = 0;
char szReply[CCH_MAXSTRING];
InputString("Enter a comma separated list of platform number(s)", szReply);
printf("\n");

// Scan through the reply string and set the bits
// dwPlatforms to correspond to the platform(s) specified
// by the user. Note that the list is a string of comma
// separated digits.
//======================================================
const char* pszReply = szReply;
while (*pszReply) {
if (*pszReply < '1' || *pszReply > '7') {
// An invalid character is present in the
// reply. Flag this error by returning zero.
//==========================================
dwPlatforms = 0;
break;
}

// Interpret the platform selector character.
//===========================================
switch(*pszReply++) {
case '1':
dwPlatforms |= PLTFRM_MSDOS;
break;
case '2':
dwPlatforms |= PLTFRM_WIN16;
break;
case '3':
dwPlatforms |= PLTFRM_WIN95;
break;
case '4':
dwPlatforms |= PLTFRM_WIN32_X86;
break;
case '5':
dwPlatforms |= PLTFRM_WIN32_MIPS;
break;
case '6':
dwPlatforms |= PLTFRM_WIN32_ALPHA;
break;
case '7':
dwPlatforms |= PLTFRM_MACINTOSH;
break;
}

// Skip any trailing whitespace after the digit.
//==============================================
while (*pszReply == ' ' || *pszReply=='\t') {
++pszReply;
}

// Skip the comma.
//================
if (*pszReply == ',') {
++pszReply;
}

// Skip white space preceding the next digit.
//=========================
while (*pszReply == ' ' || *pszReply=='\t') {
++pszReply;
}

}

return( dwPlatforms );
}






//**************************************************************************
// ConnectToDatasource
//
// Get the datasource connection information from the user and use it
// to connect to the datasource.
//
// Parameters: None.
//
// Returns:
// The connection handle or NULL if the connection failed.
//***************************************************************************
HANDLE ConnectToDatasource()
{
// Get the information we need to connect to the
// data source from the user.
//==============================================
char szServer[CCH_MAXSTRING];
char szUser[CCH_MAXSTRING];
char szPasswd[CCH_MAXSTRING];
char szDatabase[CCH_MAXSTRING];

printf("\n");
printf("**************************\n");
printf("* Connect to data source *\n");
printf("**************************\n");
InputString("SQL server name", szServer);
InputString("SQL database name", szDatabase);
InputString("User name for SQL server", szUser);
InputString("Password for SQL server", szPasswd);
printf("\n");


// Connect to a data source. SQL in this case.
// ===========================================
DATASOURCE dsParams;

dsParams.sqlParams.ds = DB_SQL;
dsParams.sqlParams.pszServer = szServer;
dsParams.sqlParams.pszUserName = szUser;
dsParams.sqlParams.pszPasswd = szPasswd;
dsParams.sqlParams.pszDbName = szDatabase;
dsParams.sqlParams.pFunc = NULL; // No encryption.
dsParams.sqlParams.pszKey = "";

HANDLE hConnect;
SMS_STATUS stat;
stat = SmsDataSourceConnect( &dsParams, &hConnect);

if (stat != SMS_OK) {
hConnect = NULL;
DisplaySmsError("Connect to data source failed", stat);
}

return( hConnect );
}







//**************************************************************************
// ViewFolder
//
// Display the folder contents. This version only displays the folder name
// and type, number of scalars, and the scalars. Other information not
// relevant.
//
// NOTE: no error checking.
//
// Parameters:
// HANDLE hFolder
// The handle of the folder to view.
//
// Returns: Nothing.
//
//**************************************************************************
void ViewFolder( HANDLE hFolder )
{
char szFolderID[SMS_DATA_BUFF_SIZE + 1]; // This folder's ID.
char szfType[SMS_DATA_BUFF_SIZE + 1]; // Folder's tag.
DWORD fType; // Folder's type.
DWORD ctScalars; // How many scalars in this folder.
SMS_STATUS stat;


// Get folder ID and type.
// -----------------------
stat = SmsGetFolderID( hFolder, szFolderID );
if (stat == SMS_NEW_FOLDER) {
strcpy( szFolderID, "New folder without an ID yet" );

}
else if (stat != SMS_OK) {
DisplaySmsError("ViewFolder: can't get folder ID", stat);
strcpy( szFolderID, "Couldn't get the folder ID" );
}

printf("============== %s ===========\n", szFolderID);

stat = SmsGetFolderType( hFolder, &fType, szfType );
if (stat != SMS_OK) {
DisplaySmsError("ViewFolder: can't get folder type", stat);
}

printf("SCALARS FOR FOLDER %s\n", szFolderID);

// Get count of scalars.
// ---------------------
stat = SmsGetScalarCount( hFolder, &ctScalars );
if (stat != SMS_OK) {
DisplaySmsError("ViewFolder: can't get scalar count", stat);
}
printf("%s (%s) contains %d scalars\n", szFolderID, szfType, ctScalars);


// Display the scalars.
// --------------------
DisplayScalars( hFolder );


// Get the folder count
DWORD ctFolders;
stat = SmsGetFolderCount(hFolder, F_ANY, &ctFolders);
printf("%s (%s) contains %d sub-folders\n", szFolderID, szfType, ctFolders);
for (DWORD dwFolder = 0; dwFolder < ctFolders; ++dwFolder) {
printf("Getting subfolder\n");
HANDLE hSubFolder;
stat = SmsGetNextFolder(hFolder, F_ANY, &hSubFolder);
if (stat != SMS_OK) {
DisplaySmsError("SmsGetNextFolder failed", stat);
break;
}

ViewFolder(hSubFolder);

// Close the sub-folder to avoid a memory leak.
//============================================
stat = SmsCloseFolder(hSubFolder);
if (stat != SMS_OK) {
DisplaySmsError("Failed to close an open folder", stat);
break;
}
}


SmsRewind(hFolder, RW_FOLDER | RW_SCALAR);

} /* ViewFolder */





//*************************************************************************
// CreateWcl
//
// This method is called to create a WCL subfolder in
// a package folder.
//
// Parameters:
// HANDLE hFolderPkg
// This is the handle of the parent folder that the newly
// created subfolder will be inserted into. For WCL and
// program item folders, the parent folder is a package
// folder.
//
// Returns:
// HANDLE
// This is the handle of the newly created subfolder.
//
//*************************************************************************
HANDLE CreateWcl(HANDLE hFolderPkg)
{
printf("\n\n");
printf("*****************************************************\n");
printf("* Creating the workstation command line sub-folder. *\n");
printf("*****************************************************\n");
printf("\n");


HANDLE hFolderNew;
SMS_STATUS stat;
char szError[CCH_MAXSTRING];
char szReply[CCH_MAXSTRING];
DWORD dwPlatforms;

// Create the WCL folder
//======================
stat = SmsCreateFolder( hFolderPkg, F_WCL, "", &hFolderNew );
if (stat != SMS_OK) {
sprintf(szError, "SmsCreateFolder failed to create the WCL folder");
DisplaySmsError(szError, stat);
return( NULL );
}


dwPlatforms = GetPlatformSelection();


printf("\n\n");
printf("*********************************************\n");
printf("* Enter values for the WCL folder scalars. *\n");
printf("*********************************************\n");
printf("\n");

InputString("Name", szReply);
SetScalarString(hFolderNew, "Name", szReply);

InputString("Command", szReply);
SetScalarString(hFolderNew, "Command", szReply);

SetScalarDword(hFolderNew, "Flags", 0);
SetScalarDword(hFolderNew, "Platforms", dwPlatforms);



// Link the new WCL folder into the folder hierarchy. Note that
// this does not insert the folder into the datasource. Only
// SmsCommitFolder modifies the datasource.
//==============================================================
stat = SmsLinkFolder(hFolderNew);
if ((stat != SMS_OK) && (stat != SMS_PARENT_NEEDS_COMMIT)) {
sprintf(szError, "SmsLinkFolder failed to link the WCL folder");
DisplaySmsError(szError, stat);
return( NULL );
}

return( hFolderNew ) ;
}



//*************************************************************************
// CreateProgItem
//
// This method is called to create a program item subfolder in
// a package folder.
//
// Parameters:
// HANDLE hFolderPkg
// This is the handle of the parent folder that the newly
// created subfolder will be inserted into. For WCL and
// program item folders, the parent folder is a package
// folder.
//
// Returns:
// HANDLE
// This is the handle of the newly created subfolder.
//
//*************************************************************************
HANDLE CreateProgItem(HANDLE hFolderPkg)
{
printf("\n\n");
printf("*****************************************\n");
printf("* Creating the program item sub-folder. *\n");
printf("*****************************************\n");
printf("\n");

HANDLE hFolderNew;
SMS_STATUS stat;
char szReply[CCH_MAXSTRING];
char szError[CCH_MAXSTRING];
DWORD dwPlatforms;

// Create the programe item folder
//================================
stat = SmsCreateFolder( hFolderPkg, F_PROGITEM, "", &hFolderNew );
if (stat != SMS_OK) {
sprintf(szError, "SmsCreateFolder failed to create the program item folder");
DisplaySmsError(szError, stat);
return( NULL );
}



// Set the value of the scalars for the program item.
//===================================================
dwPlatforms = GetPlatformSelection();



printf("\n\n");
printf("******************************************************\n");
printf("* Enter values for the program item folder scalars. *\n");
printf("******************************************************\n");
printf("\n");

InputString("Description", szReply);
SetScalarString(hFolderNew, "Description", szReply);

InputString("Command line", szReply);
SetScalarString(hFolderNew, "Command line", szReply);

SetScalarDword(hFolderNew, "Run minimized", FALSE);
SetScalarDword(hFolderNew, "Platforms", dwPlatforms);
SetScalarString(hFolderNew, "Configure script file", "");
SetScalarDword(hFolderNew, "Search local flag", 1);
SetScalarDword(hFolderNew, "Drive mode", 1);

InputString("Registry name", szReply);
SetScalarString(hFolderNew, "Registry name", szReply);
SetScalarDword(hFolderNew, "Executable flag", TRUE);



// Link the new WCL folder into the folder hierarchy. Note that
// this does not insert the folder into the datasource. Only
// SmsCommitFolder modifies the datasource.
//==============================================================
stat = SmsLinkFolder(hFolderNew);

if ((stat != SMS_OK) && (stat != SMS_PARENT_NEEDS_COMMIT)) { 
sprintf(szError, "SmsLinkFolder failed to link the programe item folder");
DisplaySmsError(szError, stat);
return( NULL );
}

return( hFolderNew ) ;
}





//*************************************************************************
// CreatePackageFolder
//
// Create a new package folder
//
// Parameters:
// HANDLE hPackageContainer
// This is the handle to the package folder's parent, which
// is a package container.
//
// Returns:
// The package folder's handle.
//
// ====================================================================
HANDLE CreatePackageFolder(HANDLE hPackageContainer)
{
SMS_STATUS stat;
char szReply[CCH_MAXSTRING];
HANDLE hFolderPkg = NULL;
HANDLE hFolderWCL = NULL;
HANDLE hFolderProgItem = NULL;



stat = SmsCreateFolder( hPackageContainer, F_PACKAGE, "", &hFolderPkg );
if (stat != SMS_OK) {
DisplaySmsError("SmsCreateFolder failed to create the package folder.", stat);
return( NULL );
}


printf("\n\n");
printf("***************************************************\n");
printf("* Creating package folder. Select a package *\n");
printf("* type. *\n");
printf("* *\n");
printf("* S Sharing. *\n");
printf("* W Workstation. *\n");
printf("***************************************************\n");
printf("\n");

InputString("SW: ", szReply);
switch(szReply[0]) {
case 'S': case 's':
hFolderProgItem = CreateProgItem(hFolderPkg);
break;
case 'W': case 'w':
hFolderWCL = CreateWcl(hFolderPkg);
break;
}




printf("\n\n");
printf("*************************************\n");
printf("* Enter the package folder scalars. *\n");
printf("*************************************\n");
printf("\n");


InputString("Package name", szReply);
SetScalarString(hFolderPkg, "Name", szReply);

InputString("Package comment", szReply);
SetScalarString(hFolderPkg, "Comment", szReply);

// If this package contains a workstation command line, then set the
// scalars that are relevant to workstation command lines.
//==================================================================
if (hFolderWCL) {
SetScalarDword(hFolderPkg, "Share permissions", (DWORD) PACKAGE_PERMISSIONS);

InputString("Workstation root", szReply);
SetScalarString(hFolderPkg, "Workstation root", szReply);

}

// If this package contains a program item, then set the scalars
// that are relevant to program items.
//==============================================================
if (hFolderProgItem) {
SetScalarDword(hFolderPkg, "Share permissions", (DWORD) PACKAGE_PERMISSIONS);

InputString("Server root", szReply);
SetScalarString(hFolderPkg, "Server root", szReply);

InputString("Share name", szReply);
SetScalarString(hFolderPkg, "Share name", szReply);
}





// Display the folder and ask the user if he or she really wants to
// write the folder to the datasource. If the user says yes, then
// commit the subfolder's first and then the package folder. Note that
// it does not make any sense to commit the package folder before its
// subfolders because, once a folder is committed, modification is not
// allowed and it would not be possible to commit the subfolders.
//===================================================================

ViewFolder(hFolderPkg);

if (UserSaysYes("OK to write the folder to the datasource")) {

if (hFolderWCL) {
stat = SmsCommitFolder(hFolderWCL);
if (stat != SMS_OK && stat!=SMS_PARENT_NEEDS_COMMIT) {
DisplaySmsError("Failed to commit the WCL folder", stat);
goto CLOSE_FOLDERS_AND_EXIT;
}
}

if (hFolderProgItem) {
stat = SmsCommitFolder(hFolderProgItem);
if (stat != SMS_OK && stat!=SMS_PARENT_NEEDS_COMMIT) {
DisplaySmsError("Failed to commit the program item folder", stat);
goto CLOSE_FOLDERS_AND_EXIT;
}
}



// Place the package folder in the in-memory hierarchy.
stat = SmsLinkFolder(hFolderPkg);
if (stat != SMS_OK) {
DisplaySmsError("SmsLinkFolder failed on the package folder", stat);
goto CLOSE_FOLDERS_AND_EXIT;
}


// write it back to data source.
stat = SmsCommitFolder( hFolderPkg );
if (stat != SMS_OK) {
DisplaySmsError("Failed to commit the package folder", stat);
}
}

// Fall through to close the folders.

CLOSE_FOLDERS_AND_EXIT:

// Close the folder's so that memory will be freed when there are no
// references to them. A folder's memory is freed when its reference
// count goes to zero. A folder has one reference for each handle to it
// that is returned plus an additional refernce from its parent folder or
// container. Thus we close the folder handles here so that the memory
// allocated to the folders will be freed, but the memory won't actually
// be freed until the package container is closed. If you fail to close
// any handle returned to you by the SMS API, the memory for that folder
// will never be deallocated (even when the folder's container is closed).
//========================================================================


if (hFolderWCL != NULL) {
stat = SmsCloseFolder(hFolderWCL);
if (stat != SMS_OK) {
DisplaySmsError("Failed to close the WCL folder", stat);
}
}

if (hFolderProgItem != NULL) {
stat = SmsCloseFolder(hFolderProgItem);
if (stat != SMS_OK) {
DisplaySmsError("Failed to close the program item folder", stat);
}
}


return( hFolderPkg );
}


//*************************************************************************
// DisplayScalars
//
// Display a folder's scalars.
//
// Parameters:
// HANDLE hfolder
// This is the folder handle.
//
// Returns: Nothing.
//
// ====================================================================
void DisplayScalars( HANDLE hFolder )
{
SMS_STATUS stat = SMS_OK;
SCALAR scalar;
char *pszTime; // For conversion of time scalars.

// The scalars do not have their own string value buffer, so
// we allocate the buffers here and set pointers to them in the
// scalar structure.
//=============================================================
char szName[SMS_DATA_BUFF_SIZE+1];
char szValue[SMS_DATA_BUFF_SIZE+1];
scalar.pszName = szName;
scalar.pszValue = szValue;
scalar.pValue = NULL;


while (1) {

scalar.dwLen = sizeof(szValue)-1; // must tell him the size

stat = SmsGetNextScalar( hFolder, &scalar);
if (stat == SMS_NO_MORE_DATA) {
break;
}

if (stat != SMS_OK && stat != SMS_MORE_DATA) {
DisplaySmsError("SmsGetNextScalar failed in method DisplayScalars", stat);
break;
}

if (stat == SMS_MORE_DATA) {

printf("Receive buffer too small, should be %d. Data truncated\n",
scalar.dwLen);
}

// Check scalar type, display accordingly.
// ---------------------------------------
switch (scalar.scType) {
case SCALAR_STRING:
printf("\t%25s: %s\n", scalar.pszName, scalar.pszValue);
break;

case SCALAR_INT:
printf("\t%25s: %ld\n", scalar.pszName, scalar.dwValue);
break;

case SCALAR_TIME:
// Check if we have a string equivalence. If so use it.
if (scalar.bStringEquivalence) {
printf("\t%25s: %s\n", scalar.pszName, scalar.pszValue);

} else {
pszTime = ctime( &scalar.tValue );
printf("\t%25s: %s", scalar.pszName, pszTime);
}
break;

case SCALAR_BINARY:
// In this sample we won't display the binary data.
// Just tell the user its size.
printf("\t%25s (Binary - this is its size): %ld\n", scalar.pszName, scalar.dwLen);
break;
}
}

// Why did we exit (other than no more scalars)?
//==============================================
if (stat != SMS_NO_MORE_DATA) {
printf("Bad return from Scalar access: %d\n", stat);
}

printf("\n");
}










// ********************************************************************
// Helper functions.
// ********************************************************************

//**********************************************************
// DidRequestHelp
//
// Check the program's arguments to see if the user asked for
// the help screen to be displayed.
//
// Parameters:
// int argc
// The argc value from main(argc, argv)
//
// char** argv
// The argv value from main(argc, argv)
//
// Returns:
// TRUE if command line parameters included a request
// for help to be displayed.
//
//***********************************************************
BOOL DidRequestHelp(int argc, char** argv)
{
const char* pszCommand = argv[1];
if (argc==2 && (strcmp((const char*) argv[1], "-help")==0)) {
return(TRUE);
}
else {
return(FALSE);
}
}


//**********************************************************************
// DisplayHelp
//
// This function displays the samples help screen.
//
// Parameters:
// None
//
// Returns:
// Nothing.
//
//*********************************************************************
void DisplayHelp()
{
printf("\n\n");
printf("********************************************************\n");
printf("* newpkg.exe: *\n");
printf("* *\n");
printf("* This is a sample program for the SMS SDK. It can be *\n");
printf("* used to view, create, or delete packages in the SMS *\n");
printf("* database. *\n");
printf("* *\n");
printf("* Syntax: *\n");
printf("* newpkg.exe [-help] *\n");
printf("* *\n");
printf("* Switches: *\n");
printf("* -help Display this help screen. *\n");
printf("* *\n");
printf("********************************************************\n");
printf("\n");
}



//*******************************************************************
// DisplayGreeting
//
// Display the initial greeting banner.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//******************************************************************
void DisplayGreeting()
{
// For this sample, the greeting is identical to the help screen.
//===============================================================
DisplayHelp();
}




//**************************************************************************
// InputString
//
// Prompt the user to input a string and return the string in the
// specified buffer.
//
// Parameters:
// const char* pszMessage
// The user prompt to display.
//
// char* pszResult
// Pointer to the buffer where the user's input will be returned.
//
// Returns;
// The user's input is returned via the given buffer.
//***************************************************************************
void InputString(const char* pszMessage, char* pszResult)
{
printf("%s: ", pszMessage);
gets(pszResult);
}


//**************************************************************************
// UserSaysYes
//
// Prompt the user to reply yes or no. If the user enters "Y" then
// return TRUE, otherwise FALSE.
//
// Parameters:
// const char* pszPrompt
// The string used to prompt the user
//
// Returns:
// TRUE = User replied "Y" or "y"
// FALSE = User gave any other reply.
//**************************************************************************
BOOL UserSaysYes(const char* pszPrompt)
{
printf("%s? [y/n]", pszPrompt);
char szReply[CCH_MAXSTRING];
gets(szReply);

return(szReply[0] == 'y' || szReply[0] == 'Y');

}



/* EOF: newjob.cpp */