Novell Home

How to Use GroupWise Tokens

Articles and Tips: article

Glade Monson
Developer Support Engineer
Americas Developer Support
gmonson@novell.com

01 Dec 2000


The GroupWise Token Commander API gives the user the ability to publish internal token events in the GroupWise client. This AppNote explains how to use this API effectively in developer applications, including accessing the Token Commander and publishing tokens through its Execute method. It also provides detailed code samples in Visual Basic, Delphi, and Visual C++.

Introduction

The GroupWise Token APIs give the user the ability to programmatically "publish" or "subscribe" to internal token events in the GroupWise client. These token events are the same low-level and high-level events which occur when a GroupWise user is taking some action at the console - such as bringing up a Calendar View, doing an edit operation inside an e-mail message, or creating a rule. By "publishing" a token, a user can simulate the effect of actions taken by a user at the client console. This is done by passing a GroupWise token from the user's application to the GroupWise client so that the client can act on it. By "subscribing" to a token, a user can intercept the intended action, modify it, add to it, or even stop it from occurring altogether.

There are literally hundreds of these tokens, each representing some structure of information necessary for proper routing and handling of its intended action inside the GroupWise client. The structure of a token includes a token ID necessary for its proper internal routing. As of this writing, there are currently 532 tokens that have been exposed for use by developers. They have been documented at the Novell Developer site for GroupWise components (see http://developer.novell.com/ndk/doc.htm).

This AppNote explores the use of the GroupWise 5.x Token Commander, which is the API set that gives you the ability to "publish" these tokens. (It replaces the older DDE publishing interface). The focus will be on the ability to easily publish different types of tokens in the three languages normally used to access this API, including Visual Basic, Delphi, and Visual C++. Complete examples that illustrate the basic concepts will be given in each language.

This AppNote will not only help you to use the GroupWise 5.x Token Commander effectively, but also gain an appreciation of the powerful means offered by the Token Commander to extend GroupWise functionality and usefulness.

Important Considerations in Using the Token Commander

Several important factors must be kept in mind when using the Token Commander. These factors should first be reviewed before beginning a discussion on how to write Token Commander code.

GroupWise Client Needs to be Running

Since the GroupWise 5.x Token Commander API operates by publishing tokens within the GroupWise client, the GroupWise client needs to be up and running when the API is invoked. If the GroupWise client is not up, the Token Commander will assume responsibility to start up the client and then process the token. This makes sense because the Token Commander causes client actions to occur. Many of the GroupWise tokens bring up GroupWise interfaces such as dialog boxes asking for information.

This Token Commander requirement stands in sharp contrast to that of the GroupWise Object API. The GroupWise Object API does not require the GroupWise client to be running. The Object API has only one possible GroupWise interface, and this can only occur at login. There may be some overlap between these two APIs, but basically the GroupWise Object API is aimed at accessing and manipulating the GroupWise information store rather than manipulating the client itself.

Token Commander is Often used together with GroupWise C3POs

The best format for implementing the Token Commander is probably in combination with another GroupWise developer component called a C3PO (Custom 3rd-Party Object) Why is this so?

A GroupWise C3PO gives you the ability to add new GroupWise menu items and toolbar buttons to the GroupWise client, and create handlers for these new items. It can also be used to create handlers for a number of the GroupWise commands and events. The Token Commander cannot do this. However, the Token Commander can be easily invoked inside one of these C3PO handlers. In fact, it is a perfect place to do so since the client is already up and running. Use of a C3PO together with the Token Commander makes a perfect partnership.

For example, suppose that a client user wants, on occasion, to compose a new mail message to a particular recipient that has lots of preformatted information already typed in the message. Preformatting as much information as possible in this new message would save the user lots of typing. To give a client user this ability, the C3PO developer could design a new toolbar button or menu item on the GroupWise client. Inside the handler for this item, the Token Commander could publish a token that would bring up the compose message dialog box. Other tokens could then be published to add whatever text is necessary to any fields of this message. The final result for the user, on pressing the new toolbar button or menu item, would be the display of a compose mail dialog popup that was already partially filled out.

Another useful and similar example would be to insert additional text into an outgoing message when the user clicks on the send button, such as a disclaimer. A C3PO, or even a Third Party Handler (another GroupWise component), would team up nicely with the Token Commander to accomplish this goal.

Tokens Must Only be Used in Their Proper Contexts

When using the GroupWise client, many actions only make sense if performed after taking certain other actions. Likewise, there are some tokens that should only be published if the proper environment exists first.

For instance, if you publish a token that selects all the text on the current line, this token will fail unless there is currently some text line available in the client on which to operate. Some message view would have to be open with the focus in the right place. In addition, many of the tokens require "handles" which are first acquired by publishing other tokens first. Therefore, the context and order in which a token is thrown are important.

GroupWise Token Commander is Built on COM Technology

The GroupWise client makes its services available to other applications through the Common Object Model (COM) technology. Using COM technology, objects known as COM objects provide interfaces through which one application can gain the services of another by accessing those interfaces. This makes it possible for a non-GroupWise application to do GroupWise client tasks.

In general terms, this type of programmable COM interface access is known as "automation", or more generally as, "OLE automation."

The Token Commander is built on this COM methodology. Any language used to invoke the Token Commander must therefore be capable of supporting automation. Visual Basic, Delphi, and Visual C++ can all do so. Hence, these are the languages normally used to access the Token Commander and other GroupWise developer components supporting automation.

The negative aspect of this type of structure is that there is usually a bit of work involved in programmatically using COM interfaces. Hence, you may think that using the Token Commander requires extra coding effort; however, Visual Basic and Delphi make this coding easy by hiding many of the access details.

Accessing the Token Commander

The actual publishing or throwing of a token takes place in two steps. The first step is to gain access to the Token Commander object. The second step is to call the "Execute" method of this Token Commander object. The Execute method will take as a parameter the token string to be published, and will also return a string value indicating whether or not it was successful.

The first step is to gain access to the Token Commander object. This will connect the Token Commander object to the application. Here are the methods used to gain this access in each of the three languages used in this article:

Visual Basic

Dim vCommander As Object (or Variant)
Set vCommander = CreateObject("GroupWiseCommander")

Delphi

var vCommander : variant;
vCommander := CreateOleObject('GroupWiseCommander');

Visual C++

CoInitialize(NULL);
IGWCommander *pvCommander = NULL;
int result = CoCreateInstance (CLSID_GWCommander, NULL, 
	 CLSCTX_ LOCAL_SERVER,
	 IID_IGWCommander,  (LPVOID
	 *)&pvCommander);

Notice that it is much easier to use Visual Basic or Delphi to get this initial Token Commander object than it is in Visual C++. For these languages, the functions "CreateObject" and "CreateOleObject" are hiding much of the COM interface complexity beneath the covers.

For example, COM interfacing normally requires a "CoCreateInstance" call. This call is shown in the Visual C++ example, but not in the Visual Basic or Delphi examples. In these two languages, the CoCreateInstance call is hidden. The CLSID reference above is also hidden, since the CreateObject or CreateOleObject calls use the string argument "GroupWiseCommander" as a programmatic reference in the system registry to look up the appropriate CLSID value - which is passed on to the CoCreateInstance function as a parameter. Similar code simplification occurs when using the Token Commander Execute function discussed later.

The reason "Set" is used in Visual Basic is because "Set" is required to create a reference variable to an outside object. It actually points to the outside variable returned from CreateObject, and does not assign this variable.

If access to the Token Commander object fails for some reason, the "result" variable in Visual C++ will indicate success or failure. In Visual Basic or Delphi, an invalid vCommander object can be trapped by normal error handling.

Executing the Token Commander

The nice thing about using the Token Commander object is that there is only one method available. It is called the "Execute" method. Using this method publishes the token. The syntax of this method is given below:

WORD  Execute (ANSISTRING  Cmd; ANSISTRING RetString)
  • Cmd: The first parameter, Cmd, is an ANSISTRING used to indicate which token the developer wishes to publish to the GroupWise client. This token string sometimes requires care in formulating because it can consist of different types of arguments. Here is a token example.

VOID ItemListSort( DWORD Handle; ENUM SortKey; [ANSISTRING
	 SortName]; ENUM SortOrder)

As shown above, the token strings themselves look like function names with parameters. Their arguments are of different types, such as ANSISTRING, WORD, BOOL, etc. About half of the tokens have parameters and half don't. Tokens without any parameters are the easiest type to code. When parameters are required for a token, such as the token shown above, the parameters will be separated from each other by a semicolon.

In addition, many times the token parameters can be optional. These types of optional tokens are enclosed in brackets, also shown above. If the user does not wish to use an optional parameter, he can simply leave that field blank - thus often resulting in two semicolons being placed together. Thus, to publish the above token without the third parameter, use the token in this form:

"ItemListSort (Handle;SortKey;;SortOrder)."
  • RetString: The second parameter in the Execute function, RetString, is an ANSISTRING used to contain the return value of a given token, (if the token has a return value). Regardless of whether a given token returns an ANSISTRING, a WORD, or some other value, RetString passes it back as a string. This value can then be transferred later to the appropriate type if necessary. If the Execute function is not successful, this string will contain some error value.

  • Return value: The return value of the Execute function, of type WORD, indicates whether or not the execution of the token succeeded. It will contain a value of 1 if the token succeeded, and 0 if the token execution failed.

Code Samples

Now that we have reviewed some of the basics, lets write some code which actually publishes a few GroupWise tokens. This should help identify how all the pieces we have discussed fit together.

For more information on GroupWise tokens visit http://developer.novell.com/ndk/doc.htm. At this site you will find the GroupWise 5.x Tokens component, which includes an excellent discussion of tokens in general, as well as a complete reference to all 532 currently available tokens (as of this writing). Each token lists its parameters and return value.

The following examples will use a variety of tokens. These tokens have different functions as well as different types of parameters. This should give you a feel for how to use any token correctly. Comments provide an explanation of how these tokens are created. The comments given for this first example in Visual Basic are more lengthy, including explanations of different token options, since many of these comments will apply to other languages as well.

Sample Application in Visual Basic

Let's take an example discussed earlier. A user wants to press some new menu item and have a compose message dialog pop up with some of the mail message fields already filled out. The following code would therefore be inserted in the handler for the new menu item in a C3PO.

  1. Bring up the new mail dialog.

    Dim iRet As Integer
    Dim ParamStr As String
    Dim sResult As String
    Dim MyMessageID As String
    Dim MyTxt As String
    Dim Number As Integer
    
    	 ParamStr = "ViewOpen(276)"
    	 iRet = vCommander.Execute(ParamStr, sResult)
    'OR
    	 iRet = vCommander.Execute("ViewOpen(276)", sResult)
    'OR
    	 Number = 276
    	 ParamStr = "ViewOpen(" + Str(Number) + ")"
    	 iRet = vCommander.Execute(ParamStr, sResult)
    'OR
    	 Number = 276
    	 iRet = vCommander.Execute("ViewOpen(" + Str(Number) +")", sResult)
    'OR
    	 iRet = vCommander.Execute("NewMail()", sResult)

    Notice first that there may be more than one way of doing some GroupWise client tasks. In the examples above, the token "NewMail" is equivalent to using the "ViewOpen" token with an argument of 276 which represents a new mail dialog. Another number would represent some other type of dialog.

    Note: In cases where a numeric value cannot be used directly, such as when the user only has access to a certain integer variable rather than the integer itself, (the user has access to "Number" and not the integer 276), the number must be converted to a string for use in the Execute function. This requires that several sub-strings be concatenated together. This is shown in the third and fourth examples above. Remember, the first argument of the Execute function must be a string.

    After calling this function to open a new mail view, the "iRet" value can then be tested to see if the token was successful. A value of 1 indicates success, and 0 indicates failure.

    By way of contrast, a couple of UNSUCCESSFUL ways to publish a token are given below.

    'ParamStr wrongly uses the string "ViewOpen(Number)" rather than 
    	 	 "ViewOpen(276)
    Number = 276
    ParamStr = "ViewOpen(Number)"
    iRet = vCommander.Execute(ParamStr, sResult)
    
    'This example shows a mismatched data type when trying to
    'concatenate the string "ViewOpen(" with an integer value 
    'represented by Number
    Number = 276
    ParamStr = "ViewOpen(" + Number + ")"
    iRet = vCommander.Execute(ParamStr, sResult)
  2. Insert a recipient named John Doe into the "TO" box.

    Before showing how to do this, it is worthwhile to review a Visual Basic rule for inserting double quotation marks inside a string. The rule states that once double quotation marks are used to start a string, the end of the string will occur at the next double quotation mark that is NOT followed IMMEDIATELY by another double quotation mark. If two double quotation marks do appear immediately together after the initial double quotation mark that starts the string, the first double quotation mark is actually used as an escape character to signify that the next double quotation mark is to be inserted into the string. It is equivalent to the "\" character in C++, except it is more confusing because in the case of Visual Basic the escape character is the same character used to delineate the string.

    ParamStr = ""	 means an empty string
    ParamStr = """	 means a string with one quote inside, but no end
    	 of the string
    ParamStr = """"	 means a string with one quote inside

    Knowing this rule, here are several successful ways to add John Doe into the "TO" box as the recipient of the message. The ItemSetText token requires an ANSISTRING variable as the first parameter that indicates the ID of the open mail message. The second parameter is a number indicating to which field the text will be inserted, and the third parameter is another ANSISTRING variable indicating what should be inserted in the field. These ANSISTRING values need to have double quotation marks around them.

    	 MyMessageId = "X00"
    	 MyTxt = "John Doe"
    
    	 ParamStr = "ItemSetText(""" + MyMessageId + """; 0; """ + MyTxt 	 
    	 	 	 	 	 	 	 	 + """)"
    	 iRet = vCommander.Execute(ParamStr, sResult)
    ' OR
    	 iRet = vCommander.Execute("ItemSetText(""" + MyMessageId +
    	 	 	 	 	 	 	 	 	 """;0;""" + MyTxt + """)", sResult)
    'OR
    	 ParamStr = "ItemSetText(""X00""; 0; """ + MyTxt + """)"
    	 iRet = vCommander.Execute(ParamStr, sResult)
    'OR
    	 ParamStr = "TextSetTo(""" + MyTxt + """)"
    	 iRet = vCommander.Execute(ParamStr, sResult)
    'OR
    	 ParamStr = "FocusSet(0)"
    	 iRet = vCommander.Execute(ParamStr, sResult)
    
    	 ParamStr = "Type(""" + MyTxt + """)"
    	 iRet = vCommander.Execute(ParamStr, sResult)

    The first example works because it is concatenating five strings together (shown here without the quotation delimiters around the strings):

    • ItemSetText("

    • MyMessageID

    • ";"

    • MyTxt

    • ")

    The second example is the same as the first except it does all the work on one line. Which is preferred is a matter of style. The third example works because it concatenates the following three strings:

    • ItemSetText(" X00" ;0;"

    • MyTxt

    • ")

    Other examples are possible, such as the fourth and fifth examples above.

    Note: The MyMessageId string is assigned as "X00". This is the value a developer should always use when creating a new message in the client. The permanent message ID has not yet been assigned, and so the new draft message is assigned a temporary ID equal to "X00".

    Be aware that to do something with an already existing message, such as opening it or getting attributes from it, the actual message ID of the existing message may be required. The token "ItemOpen" is an example which requires such an ID. This ID can be found by first publishing the token called "ItemMessageIDFromView", or can be found from other methods such as using a saved ID value. You can even get it from a MAPI function call since the MAPI Message IDs are compatible with GroupWise Message IDs.

    By way of contrast, next is an example that will not work because the VB escape rule is not used properly. Since the first double quote appears as one quote in the string, without an end to the string, the characters that follow the first double quote will be mistaken as text. Hence, "MyMessageID" will appear in the string rather than "X00".

    ' won't work
    MyTxt = "John Doe"
    ParamStr = "ItemSetText("" + MyMessageId + "";0;"" + MyTxt + "")"
    iRet = vCommander.Execute(ParamStr, sResult)
  3. Insert other values into the compose message dialog.

    Now let's insert the subject of the message. It will be "What the fox did". The body text will be "The quick brown fox jumped over the lazy dogs". We will then italicize the last two words "lazy dogs".

    Since we have already shown that there may be more than one token which will accomplish a task, as well as demonstrated that there are various syntax possibilities for publishing a token, from now on we will limit ourselves to just one method of accomplishing some action.

    'Add the subject field
    MyTxt = "What the fox did"
    ParamStr = "ItemSetText(""" + MyMessageId + """; 9; """ + MyTxt +
    """)"
    iRet = vCommander.Execute(ParamStr, sResult)
    
    'Add the body text field
    MyTxt = "The quick brown fox jumped over the lazy dogs"
    ParamStr = "ItemSetText(""" + MyMessageId + """; 10; """ + MyTxt +
    """)"
    iRet = vCommander.Execute(ParamStr, sResult)
    
    'Position the cursor immediately before the last two words "lazy
    `dogs".  Make sure the focus is in the body text field (which it
    `should be), go to the end of the line, and then backtrack two
    `words
    ParamStr = "FocusSet(10)"
    
    iRet = vCommander.Execute(ParamStr, sResult)
    ParamStr = "PosLineEnd()"
    iRet = vCommander.Execute(ParamStr, sResult)
    ParamStr = "PosWordLeft()"
    iRet = vCommander.Execute(ParamStr, sResult)
    ParamStr = "PosWordLeft()"
    iRet = vCommander.Execute(ParamStr, sResult)
    
    'Now select the text to be replaced, and type in the new
    `italicized version
    ParamStr = "SelectToEndText()"
    iRet = vCommander.Execute(ParamStr, sResult)
    
    ParamStr = "FontItalic()"
    iRet = vCommander.Execute(ParamStr, sResult)
    
    MyTxt = "lazy dogs"
    ParamStr = "Type(""" + MyTxt + """)"
    iRet = vCommander.Execute(ParamStr, sResult)

Sample Application in Delphi

Using the Token Commander in Delphi is very similar to using it in Visual Basic. It may even be a little easier to use because strings are surrounded by a single quotation mark on both sides of the string, and not by double quotation marks. Thus, the same escape character rule that applies in VB does not apply in Delphi.

Here are a couple of simple Delphi examples. In the first example, a user would like to increase the font size of an incoming mail message. One way to do this would be to implement a C3PO that captures the "open" mail command. Inside this handler, the normal functionality for opening this message would be allowed to continue. The mail message would then open, meaning the ViewOpen token would not be needed as in the last example. At that point, still inside the handler for the open mail message, the Token Commander would access the body text and set the font size for this text to some larger amount.

Here is some slightly modified code to demonstrate this technique. Since showing C3PO code here would require too much space, the "NewMail" and "ItemSetText" calls are used as a substitute to first set up the proper environment. Then a token is thrown to enlarge the font size of the mail message.

var vCommander : variant;
var ParamStr : String;
var iRet : Integer;
var sResult : String;
var FontName : String;
var MyMessageID : String;
var MyTxt : String;

	 vCommander := CreateOleObject('GroupWiseCommander');

	 // create the new mail message
	 ParamStr := 'NewMail()';
	 iRet := vCommander.Execute(ParamStr, sResult);

	 //  insert some body text
	 MyMessageID := 'X00';
	 MyTxt := 'The quick brown fox jumped over the lazy dogs';
	 ParamStr := 'ItemSetText("' + MyMessageID + '";10;"' + MyTxt +
'")';
	 iRet := vCommander.Execute(ParamStr, sResult);

	 //  Set the focus to the body text field
	 ParamStr := 'FocusSet(10)';
	 iRet := vCommander.Execute(ParamStr, sResult);

	 // Select all the text in the body text field
	 ParamStr := 'PosTextTop()';
	 iRet := vCommander.Execute(ParamStr, sResult);

	 ParamStr := 'SelectToEndText()';
	 iRet := vCommander.Execute(ParamStr, sResult);

	 //   change the font size
	 FontName := 'Times New Roman';
	 ParamStr := 'FontSet("' + FontName + '";-16;700)';
	 iRet := vCommander.Execute(ParamStr, sResult);

It should be mentioned that due to a small quirk in current Token Commander code, the above code will not work with HTML messages with the GroupWise Enhancement Pack 5.5.3.1 version. It will only work with RTF messages. However, this has been fixed in the new Bullet Proof release which will be available in early 2001.

Here is another quick Delphi example. This code will get a folder handle, and then use that folder handle to get all of the folder names in a user's folder list. They will then be listed in a Delphi list box. Assume for this example that the variables are already typed.

// get the folder handle
ParamStr := 'FolderListCreate(7)';
iRet := vCommander.Execute(ParamStr, MyFolderHandle);

i := 0;
iRet := 1;

// get all the folder names and put them in a list box
// repeat
	 ParamStr := 'FolderListGetName(' + MyFolderHandle + ';'
	 	 	 	 	 	 	 	 + IntToStr(i) + ';1)';
	 iRet := vCommander.Execute(ParamStr, MyFolderName);
	 i := i + 1;
	 if (iRet = 1) then begin
	 	 ListBox1.Items.Add(MyFolderName);
	 end;
until iRet = 0;

Sample Application in Visual C++

Using the Token Commander in Visual C++ presents the most challenges. It simply takes more code to accomplish the same tasks because the COM complexity is not hidden. The COM interfaces must be dealt with directly.

This example will create a rule that will take all of the incoming mail from someone named "John Doe" and put all this mail in a folder called "NotImportant".

CoInitialize(NULL);

// create a pointer to a wide character array (needed in COM).  This array
// will be used to store each token as it is created.
wchar_t* pTknStr = new wchar_t [200];

// initialize some values, including the rule name
char* pMyName = "John Doe";
char* pMyRule = "ReRouteIt";
char* pFldName = "John Doe\\NotImportant";

// initialize the Token Commander pointer
IGWCommander *pGWC = NULL;

//  Get the pointer to the Token Commander, which will be used throughout the sample
int result = CoCreateInstance(CLSID_GWCommander, NULL,  CLSCTX_LOCAL_SERVER, 
	 	 	 	 	 	 IID_IGWCommander, (LPVOID*)&pGWC);

// make sure it was successful
if (!SUCCEEDED(result))
	 	 return 0;



******************** 1st token ********************

// Before we create the rule, we need to create the appropriate filter. 

//  Publish the first token. This will create a empty filter (150) for the inbox (6).
// The success value will indicate whether the token was published successfully. All
// string values need to be in wide character format. BSTR types must be used.
BSTR cmd = ::SysAllocString(L"FilterCreate(150;6)");
BSTR res = NULL;
BSTR hFilter = NULL;
VARIANT_BOOL success = FALSE;

// get the filter handle as the return value
// The variable "success" can be used to determine whether or not the token executed
// successfully. An example is shown for the first token, but skipped for the other 
// tokens to conserve space.
pGWC->Execute(cmd, &hFilter, &success);
// don't release the hFilter object yet.  It will be needed
::SysFreeString(cmd);

if (!success){

	 // do necessary cleanup
	 ::SysFreeString(hFilter);

	 pGWC->Release();

	 CoUninitialize();
	 return 0;

}
	 

******************** 2nd token ********************

// Next, set the text for the filter based on whom the mail item is from
wcscpy(pTknStr, L"\0");

// convert John Does name to a wide string
int len1 = strlen(pMyName);
wchar_t* pwMyName = new wchar_t[len1 + 1];
mbstowcs(pwMyName, pMyName, len1 + 1);

// concatenate the string together to form the token. Note the use of the C escape
character
wcscpy(pTknStr, L"FilterSetText(");
wcscat (pTknStr, hFilter);
wcscat (pTknStr, L";1;\"");
wcscat (pTknStr, pwMyName);
wcscat (pTknStr, L"\";165)");

cmd = ::SysAllocString(pTknStr);
res = NULL;
success = FALSE;

pGWC->Execute(cmd, &res, &success);
::SysFreeString(cmd);
::SysFreeString(res);

delete pwMyName;



******************** 3rd token ********************

// next, set the item type to filter on mail
wcscpy(pTknStr, L"\0");

// concatenate the string together to form the token
wcscpy(pTknStr, L"FilterSetItemType(");
wcscat (pTknStr, hFilter);
wcscat (pTknStr, L";276;1)");

cmd = ::SysAllocString(pTknStr);
res = NULL;
success = FALSE;
	 
pGWC->Execute(cmd, &res, &success);
::SysFreeString(cmd);
::SysFreeString(res);

******************** 4th token ********************

// next, create the rule for a new item
wcscpy(pTknStr, L"\0");

// convert the rule name to a wide string
len1 = strlen(pMyRule);
wchar_t* pwMyRule = new wchar_t[len1 + 1];
mbstowcs(pwMyRule, pMyRule, len1 + 1);
	 
// concatenate the string together to form the token
wcscpy(pTknStr, L"RuleCreate(;\"");
wcscat (pTknStr, pwMyRule);
wcscat (pTknStr, L"\";185;;");
wcscat (pTknStr, hFilter);
wcscat (pTknStr, L")");

cmd = ::SysAllocString(pTknStr);
res = NULL;
success = FALSE;
	 
pGWC->Execute(cmd, &res, &success);
::SysFreeString(cmd);
::SysFreeString(res);

// don't delete the pwMyRule pointer until later



******************** 5th token ********************

// next, add the move to folder rule
wcscpy(pTknStr, L"\0");

// convert the folder name to a wide string
len1 = strlen(pFldName);
wchar_t* pwFldNam = new wchar_t[len1 + 1];
mbstowcs(pwFldNam, pFldName, len1 + 1);
	 
// concatenate the string together to form the token
wcscpy(pTknStr, L"RuleAddActionMoveToFolder(;\"");
wcscat (pTknStr, pwMyRule);
wcscat (pTknStr, L"\";\"");
wcscat (pTknStr, pwFldNam);
wcscat (pTknStr, L"\")");

cmd = ::SysAllocString(pTknStr);
res = NULL;
success = FALSE;
	 
pGWC->Execute(cmd, &res, &success);
::SysFreeString(cmd);
::SysFreeString(res);

delete pwFldNam;
delete pwMyRule;

******************** 6th token ********************

// finally, delete the filter handle so system resources won't be lost	 wcscpy(pTknStr, L"\0");

// concatenate the string together to form the token
wcscpy(pTknStr, L"FilterDelete(");
wcscat (pTknStr, hFilter);
wcscat (pTknStr, L")");

cmd = ::SysAllocString(pTknStr);
res = NULL;
success = FALSE;

pGWC->Execute(cmd, &res, &success);
::SysFreeString(cmd);
::SysFreeString(res);

//  clean up
::SysFreeString(hFilter);
pGWC->Release();
CoUninitialize();

return 0;

Conclusion

This AppNote has shown how the GroupWise Token Commander can be used in an application to publish internal GroupWise token events to the GroupWise client. This can be a powerful aid to GroupWise developers, allowing them to add considerable functionality and usefulness to accomplish GroupWise client tasks.

Copyright 2000 by Novell, Inc. All rights reserved. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying and recording, for any purpose without the express written permission of Novell.

All product names mentioned are trademarks of their respective companies or distributors.

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© 2014 Novell