> developer support home

SEPTEMBER 1994 VOLUME 6 NUMBER 4


INDEX


ARTICLES

Telephony SDK Services for PC Telecommunications

Like any software developer, I often try to dream up a software idea that hasn't already been written by 10 or 20 other companies. I have found the solution to this problem; for the first time I can work on a project that hasn't been done a thousand times over. I recently joined the Developer Support group at Novell and was given responsibility for supporting the Telephony SDK, so I started diving into the realms of PC telecommunications. I'll give you a brief description of the Telephony SDK and the services it provides.

I'm not going to describe all of the requirements for running Novell NetWare Telephony Services on Novell NetWare. These requirements are fully explained in the January and February, 1994 editions of Novell's Application Notes. (Call 1-800-377-4136 for information on Application Notes). Once you have the NetWare Telephony Services (TSERVer) installed and functioning, assuming you have the Telephony Services API (TSAPI) SDK, you can begin writing TSAPI applications. What fun it is to run a program that can call someone from your desk without even touching your phone! And what frustration fellow engineers feel as you ring their phones over and over again just to see your program in action! But enough of that--what can the Telephony SDK actually do?

How TSAPI Works

As shown in Figure 1 on page 1, TSAPI is actually composed of two parts. The first part is the TSERVer piece, a NetWare Loadable Module (NLM) for the NetWare file server. This piece responds to requests made by client workstations that want Telephony services performed. Then the TSERVer formats these requests correctly and passes them on to the second part of TSAPI, a Private Branch Exchange (PBX) device driver (the software portion that transfers the requests from the NetWare file server to the phone control system). Based on the PBX hardware you have installed, you will have a different PBX driver loaded on your NetWare file server. However, the TSERVer NLM remains the same.

The TSERVer NLM and the PBX driver work together to provide telephony functionality, but some of these features are not available on all PBXs. For example, although the TSERVer supports predictive dialing, many PBXs do not. Therefore, when you begin programming you will need to decide which specific PBX you will work with. The alternative is to decide on a smaller set of basic TSERVer functions to implement, most likely available from all PBXs. Every PBX driver will come with a programmer's manual describing which TSERVer function calls are available and implemented by their specific PBX driver.

Currently, the TSAPI supports two platforms: Windows and server NLMs. Applications written for either of these platforms can make TSAPI requests from the TSERVer. In the future other platforms will be supported.

TSAPI provides many services including making a call from one device (typically a telephone) to another; putting calls on hold; transferring calls to another device; making conference calls; and hanging up or clearing a call. Other services include advanced features such as predictive dialing.

The NetWare Telephony Services SDK includes a sample application using many of the basic call control features. For instance, the included rolodex-type program (TSCALL.EXE) lets you click on a name and push a "dial" button to connect your phone with theirs.

From there, the ideas are up to you! You could write applications for a software controlled "hunt group" for sales people or a call control center. An administrative assistant may even use your yet-to-be-written program to conference with several members of your department. Most of the basic features and some of the advanced features of phone systems have already been implemented, and more changes are scheduled for the future.

SDK Debugging Tools

The SDK also includes debugging tools to help developers test their applications and to help determine where bugs lie when TSAPI calls don't appear to be working. For developers who don't have access to a PBX or who wish to do their application testing away from a production environment PBX, a PBX simulator can emulate a physical PBX. No PBX is physically connected to the TSERVer running the simulator. TSERVer simply acts as if it were a PBX and keeps track of information on "fake" phones appearing to be available to a telephony application.

Another debugging tool is CSTASPY, which can track all incoming and outgoing telephony messages as they occur. When something doesn't appear to be working as desired, check this log to see if the events that actually occurred are the same as the events you desired.

If you need developer support, call 1-800-NETWARE. In this and future issues of Bullets, read "TeleTips." Look for telephony articles in future Developer Notes as well as our fax server. If you have questions or comments feel free to leave them with us. As you begin telephony coding, remember Novell's Developer Support department will help you get your cutting-edge programs to the market, and we're always open to suggestions and comments to make our product more useful to you.

Developing in the UnixWare Environment

Since the release of UnixWare 1.1 UnixWare has been increasingly used as an application server. As a result, many applications are written for and ported to UnixWare. Many existing UNIX applications were designed to operate on USL UNIX SVR4.2, a predecessor of UnixWare. These applications require very little porting effort to make them work with UnixWare. However, with many other variants of UNIX available in the marketplace, developers require special consideration porting applications from these systems.

The Novell UnixWare Developer Support group has found that many UNIX developers encounter common problems. Novell intends to help UnixWare developers get going in the right direction by covering various aspects of the UnixWare development environment, common development problems and possible solutions.

To develop on UnixWare, you need (in addition to either a Novell UnixWare Application Server or UnixWare Personal Edition) the Novell UnixWare Software Developers Kit version 1.1. The SDK has everything you need to develop Motif GUI applications, Windowing Korn Shell (wksh) applications, device drivers, networking applications and character-based applications. The SDK also includes online documentation, a Pentium(TM) C compiler, an enhanced debugger and sample source of drivers and applications.

Installing UnixWare

The first thing you will notice when you open the Novell UnixWare SDK "Red Box" is the apparent lack of documentation. To lower the cost of the Novell UnixWare SDK to US $95 Novell replaced printed documentation with online documentation available through the Fingertip Librarian. If you prefer, you can purchase printed documentation separately. To open the online documentation you must install the "guides" package. Once "guides" is installed start up the Fingertip Librarian to produce a list of all available documentation. For C developers Novell highly recommends that you read the "Programming in Standard C" guide which contains the information necessary to use the C compiler and the enhanced debugger.

After installing the UnixWare SDK and reading the online documentation system, you should consult the sample source. It is easier to start from a sample application or driver than to start development from scratch. Sample source is available in several directories, although the primary directory for sample source is the /usr/src directory. Two subdirectories are under /usr/src: the ihvsrc directory, containing sample device drivers; and the isvsrc directory, containing a sample OpenLook GUI application. For Motif GUI sample applications look into the /usr/X/lib/ motifdemos directory and for Windowing Korn Shell samples look into the /usr/X/lib/wksh directory.

Compiling Sample Motif Applications

If you want to compile sample Motif applications, change to one of the sample directories. For this example we will change to the directory of /usr/X/lib/motifdemos/hellomotif. This directory should contain the files in Figure 2.

To run the "make" command to build the hellomotif binary, you need a "Makefile." To convert the Imakefile into a Makefile, run the /usr/X/lib/config/xmkmf in Figure 3. Executing the ls-l command will show the resulting Makefile (see Figure 4).

Now you can execute the "make" command and get the results in Figure 5. The hellomotif Motif application should now be successfully compiled.

Library Search Functions

During the process of compiling an application for UnixWare, developers often run into problems with "Undefined Symbols." During the linking phase of compiling a C program, ID consult system libraries to resolve function references. If a library has not been specified but a function in that library is referenced, then the error stating that there are "Undefined Symbols" will result. To examine the contents of libraries use the nm command. This command has the output in Figure 6 on page 4 which you can incorporate into a simple shell script such as searchlib to provide a general library search function (see Figure 7 on page 4). To determine where a symbol (bind) is defined:
$ searchlib bind
/usr/lib/libsocket.a:0x000000c0 T bind

/usr/lib/libsocket.so:0x00008050T bind
The output of the nm command will often be a list of several library definitions. Here, we see that bind is defined in the static libsocket.a and the shared object library (dynamic) libsocket.so. The library name is the path that precedes the colon; your cc command line should then include the entry -lsocket to include the socket library.

Debugging Applications

Often during the development process, you need tools to identify and eliminate bugs. Use the enhanced debugger "debug" in most situations to debug applications. For device drivers, the kernel debugger kdb is provided to track down bugs or errant panics. In addition to the debuggers, the command truss enables you to watch the execution of any application and examine the system calls used. A sample output is shown in Figure 8 on page 4.

Compiling Large Binaries

Another common problem encountered by developers of large applications or libraries is a memory error from the linker (see Figure 9 on page 5). This error often occurs because each user in the system has several per-process memory constraints and the linking process is exceeding the constraints. You can easily correct the problem by increasing several kernel tunable parameters. To increase file limit size (equivalent to ulimit):
SFSZLIM: Soft file size limit
HFSZLIM: Hard file size limit
To increase user data (process heap and brk(2)) area:
SDATLIM: Soft data limit
HDATLIM: Hard data limit
To increase user stack (stack segment) area:
SSTKLIM: Soft stack limit
HSTKLIM: Hard stack limit
To increase address space (brk(2) area) for the process:
SVMMLIM: Soft Virtual Memory limit
HVMMLIM: Hard Virtual Memory limit
Use the ulimit-a command to view the current settings of these parameters. To change the settings of these parameters, login or su to root and use the idtune command (using SFSZLIM as an example):
# cd /etc/conf/bin
# ./idtune SFSZLIM 0x7FFFFFFF
This idtune command line changes SFSZLIM to the unlimited setting. In addition, you may specify a lower value than this if you do not want it set to unlimited. View each tunable parameter's range of acceptable values by using the idtune -g command (using SFSZLIM as an example) in Figure 10 on page 5.

The first value is the current setting, the second is the default setting, the third is the minimum value and the last is the maximum value.

After you have changed all tunable parameters, you need to rebuild the kernel and shut down the system:

# ./idbuild -B
# cd / ; shutdown -g0 -y
After the system has come back up, check the new settings with the ulimit -a command. If all tunables were tuned to unlimited, you should see the results in Figure 11.

This overview of the UnixWare development environment and the frequently-encountered problems and their solutions should give you a good start developing for UnixWare. Although you will undoubtedly encounter your own problems, we hope an understanding of the available tools and problems of other developers will be of great assistance in the development process.

Figure 2: Changing to the sample directory

$ ls -l
total 50
-r--r--r--   1 root     other     1036 May 20  1993 Imakefile
-r--r--r--   1 root     other     4020 May 20  1993 hellomotif.c
-r--r--r--   1 root     other     1119 May 20  1993 hellomotif.uil
$
Figure 3: Convert the Imakefile into a Makefile
$ /usr/X/lib/config/xmkmf
imake -DUseInstalled -I/usr/X/lib/config
Figure 4: The resulting Makefile
$ ls -l
total 50
-r--r--r--   1 root     other     1036 May 20  1993 Imakefile
-rw-r--r--   1 darrend  other    17327 Aug 3  09:26 Makefile
-r--r--r--   1 root     other     4020 May 20  1993 hellomotif.c
-r--r--r--   1 root     other     1119 May 20  1993 hellomotif.uil
$
Figure 5: Successful results of executing the "make" command
$ make
        /bin/rm -f hellomotif.o
        cc -c -O -Xa -I. -I/usr/X/X11 -I/usr/X/X11 -I///usr/X/
include -I///usr/X/include/X11 -I/usr/include -I//usr/X/include
-I. -DSVR4 -DSYSV386 -DI18N -DFUNCPROTO=15 -DNARROWPROTO
-DLIBDIR=\"/usr/X/lib\" -DDESTDIR=\"/usr/X\"  hellomotif.c
        /bin/rm -f hellomotif
        cc -o hellomotif hellomotif.o -O -Xa  -T 0x8300000
-L//usr/X/lib  /usr/X/lib/libMrm.so /usr/X/lib/libXm.so -lXt
-lXext -lX11  -lgen  -lnsl -ldl -lsocket -z nodefs
$
Figure 6: Examining the contents of the libraries
$ nm /usr/lib/libc*

Symbols from /usr/lib/libc.so.1:
[Index]   Value      Size    Type  Bind  Other Shndx   Name
...
[1600]  |    209428|       4|OBJT |GLOB |0    |12     |_daylight
[1601]  |    132435|       0|FUNC |WEAK |0    |8      |execve
[1602]  |    176976|      88|FUNC |WEAK |0    |8      |unlockpt
[1603]  |    155120|     128|FUNC |GLOB |0    |8      |vfprintf
[1604]  |    129200|       0|FUNC |GLOB |0    |8      |_ioctl
[1605]  |    133616|     328|FUNC |WEAK |0    |8      |lockf
[1606]  |    192211|       0|FUNC |WEAK |0    |8      |auditevt
[1607]  |     70670|       0|FUNC |GLOB |0    |8      |_read
[1608]  |    132396|       0|FUNC |WEAK |0    |8      |execv
[1609]  |    133508|       0|FUNC |WEAK |0    |8      |getmsg
[1610]  |    156320|     480|FUNC |GLOB |0    |8      |_execvp
[1611]  |    133571|       0|FUNC |WEAK |0    |8      |getrlimit
[1612]  |    112784|      40|FUNC |GLOB |0    |8      |_toupper
[1613]  |    132120|       0|FUNC |GLOB |0    |8      |_cerror
[1614]  |    124608|      16|FUNC |GLOB |0    |8      |ferror
[1615]  |    159440|     148|FUNC |WEAK |0    |8      |tsearch
[1616]  |    192344|       0|FUNC |WEAK |0    |8      |lvlequal
Figure 7: Determining where a symbol is defined
#!/bin/sh
if [ $# -ne 1 ]
then
        echo "Usage: searchlib function_name" >&2
        exit 1
fi
# You may need to add library directories to this list.
LIBDIRS="
        /usr/lib
        /usr/ccs/lib
        /usr/X/lib
        /usr/ucblib"
for dir in $LIBDIRS
do
        for lib in $dir/*.a $dir/*.so
        do
                if [ -r "$lib" ]
                then
                        nm -px $lib | \
                         sed -n `/T \<'$1'\>/p' 2>/dev/null |
                        while read ans
                        do
                                echo $lib:$ans
                        done
                fi
        done
done

Figure 8: Sample output of truss command
$ truss hello
execve("./hello", 0x08047C58, 0x08047C60)  argc = 1
getuid()                                        = 30069  [ 30069 ]
getuid()                                        = 30069  [ 30069 ]
getgid()                                        = 1  [ 1 ]
getgid()                                        = 1  [ 1 ]
procpriv(4, 0x00000000, 0)                      = 0
sysi86(SI86FPHW, 0x80035FE4, 0x800353A4, 0x8000E295) = 0x00000000
ioctl(1, TCGETA, 0x0804668A)                    = 0
Hello, World
write(1, " H e l l o ,   W o r l d".., 13)      = 13
_exit(13)
$
Figure 9: Memory error from the linker
ld: libelf error: memory error: output file     space elf_update
error code 1 (bu21).
Figure 10: View range of acceptable values
# ./idtune -g SFSZLIM
0x1000000       0x1000000       0x2000  0x7FFFFFFF
Figure 11: Checking the tunable parameters with ulimit-a
$ ulimit -a
time(seconds)                 unlimited
file(blocks)                  unlimited
data(kbytes)                  unlimited
stack(kbytes)                 unlimited
coredump(blocks)              2048
nofiles(descriptors)          256
vmemory(kbytes)               unlimited
$

DEVELOPER NEWS

AppWare Foundation Release

Novell announces the general release of the AppWare Foundation for six major platforms: Macintosh, MS Windows, UnixWare, Sun/OS, Sun/Solaris and HP-UX. The following SDKs are available:
  • The AppWare Foundation for Macintosh 1.90 includes a prerelease SDK for native support of the Power Macintosh using Metroworks compilers.
  • The AppWare Foundation for MS Windows 1.90 includes a developer prerelease SDK for support of MS Windows NT so you can develop and deploy applications on MS Windows NT and MS Chicago when it is available.
  • The AppWare Foundation for OS/2 PM 0.85 Developer Prerelease SDK.
If you're ready to move to object-oriented programming, Novell is releasing ObjectWindows for AppWare Foundation (OW/AF) developer prerelease on the Macintosh, MS Windows and OS/2 PM platforms.

We're also launching the Early Experience Program for OW/AF. This program will allow you to take advantage of early releases of Novell and Borland's new cross-platform application framework at a lower cost (no "beta site" commitment). For more information on the OW/AF bundled SDKs or the Early Experience Program call 1-408-431-5172.


TECHNICAL INSIGHTS

Hints for Accessing Files Quickly from the NetWare NLM SDK

Novell has come up with some APIs called Advanced Services. To access a file quickly, use the following API calls:
  • AsyncRead: this reads the file directly from the file server's cache memory (if the file is already in cache)
  • qread: low overhead read operation
  • qwrite: low overhead write Note: These files are using NetWare's disk caching and transaction tracking if active. Default Disk caching on a 3.x server is 4k. On 4.x it is configurable, starting at 4k (8k, 16k, 32k or 64k). This happens at install time. All files are open in normal mode. If you want to bypass NetWare disk caching and Transaction Tracking System it enabled, Novell does not recommend using the Direct File System (DFS) calls unless:
  • Your application is doing its own caching and transaction tracking and you are experiencing performance degradation when you have both NetWare and your application's transaction tracking and disk caching.
  • Backup applications often access large amounts of data not being accessed by other applications. If these accesses are made through caching, the cache becomes nonrelevant for all other accesses, and general server performance suffers for other users.
For more detailed information on the file structures and direct file system I/O, refer to NetWare Services for NLMs, chapter 22, Direct File System services. For more information on parameters each API needs, refer to NLM Library Reference Volume I.

Use any of the following API calls:

  • DFSOpen
  • DFSClose
  • DFSCreate
  • DFSExpandFile
  • DFSFreeLimboVolumeSpace
  • DFSRead: reads sectors from a file in direct file mode (sleeps until completion)
  • DFSReadNoWait: reads sectors from a file in direct file mode (returns immediately after initiation)
  • DFSReturnFileMappingInformation: returns file extents, each with number of blocks and starting file and volume block numbers
  • DFSReturnVolumeMapping: Information: returns information about a volume required for allocation
  • DFSSetEndOfFile: sets the file size
  • DFSsopen: opens a file in direct file mode
  • DFSWrite: writes sectors into a file using DFS (sleeps until completion)
  • DFSWriteNoWait: writes sectors into a file using DFS (returns immediately after initiation)
Note: When a file is open in direct mode (DFSsopen) the server opens the file, flushes all cache entries for the file and flags the file so that future I/Os do not use caching and TTS functions.

Operating System I/O calls perform non-buffered I/O operations. Files opened at the operating-system level (with open, sopen, and create functions) are opened at the stream level.

Note: These files are using NetWare's disk caching and transaction tracking if active. Default Disk caching on a 3.x server is 4k. On 4.x it is configurable starting at 4k (8k, 16k, 32k or 64k). This happens at install time. All files are open in normal mode.

File Engine (FE) Services are used to service non-DOS file systems such as Apple's Appletalk Filing Protocol (AFP) and Sun Microsystem's Network File System (NFS). These APIs can be referenced in the NLM Library Reference Volume I (FECreat, FEFlushWrite, Fesopen and so on).

Note: These files are using NetWare's disk caching and transaction tracking if active. Default Disk caching on a 3.x server is 4k. On 4.x it is configurable, starting at 4k (8k, 16k, 32k or 64k). This happens at install time. All files are open in normal mode.

Stay tuned next month for some sample source.

Gotchas in Event Monitoring

Monitoring systems events can be a challenging area of NLM development. Not only do you have a large number of events available to monitor, but you must be aware of a number of behavior issues of both the core OS and your NLM.

You can monitor two main areas of events: system events or file system events. The two APIs for these are RegisterForEvent and NWAddFSMonitorHook, respectively. These two functions work in a similar manner; they take parameters that specify the event type you wish to monitor and the routine to be invoked when that event is generated. The routine that you provide to these event services become callback routines to the OS.

Callback routines and OS Threads

If you provide a routine as a callback routine to the system, you need to take care which operations you call in that routine. In most instances when an event is called, your routine is called from a OS thread. This means that any resources that your NLM provides or that CLIB provides will be in a different context than the context in which your callback routine is being executed. One solution is to specify the context for the execution of your routine prior to calling any functions that use CLIB context. To do this, use the GetThreadGroupID call in the main body of your program and store the result in a global variable (see Figure 12).

In the callback routine use something like the example in Figure 13. These operations will ensure that your routine is in the proper context for execution. You can find more details in the NetWare NLM Development and Tools Overview manual in the section "NLM Program Coding Issues."

Sleeping Dogs versus Sleeping Threads

It may be said that you should let sleeping dogs lie, but the same is not always true for your callback routines. Many times you cannot permit a callback routine to fall asleep. Since this is a gotcha that can bite hard, you might want to get into the habit of writing your callback routines to avoid this problem. One method that I like is to write a pair of routines for each event that I wish to monitor.

The first routine is the actual callback routine itself. In this routine I set the thread context (as shown above), copy any data passed to the callback routine to a global data structure, then SignalLocalSemaphore and exit the routine. I spin off the other routine as a independent thread somewhere in my main module. The only thing it does is WaitOnLocalSemaphore. Once the semaphore has been signaled, this routine will take the data from the global data structure and process it according to the needs of my NLM.

This may cause some additional work, but it makes a more consistent design and eases implementation of event callback routines.

Notes on RegisterForEvent API

Not all events in the list for RegisterForEvent can be called in NetWare 3.x. Event types up through event 29 (EVENT_DESTROY_PROCESS) are available to NetWare 3.x. All other events are available in NetWare 4.0x except for EVENT_CHANGE_SECURITY and EVENT_QUEUE_ACTION.
 
Figure 12: Specify the context for the execution
#include 
int globalThreadGroupID;
main()
{

globalThreadGroupID = GetThreadGroupID();
    ...
}
Figure 13: Insuring the routine is in the proper context for execution
int    oldTGID;
oldTGID = SetThreadGroupID( globalThreadGroupID );
/* Do work */
SetThreadGroupID( oldTGID );
/* always set back the thread group ID */

TELETIPS

TeleTip #1

Recently Novell released the NetWare Telephony SDK, enabling developers to create software to control telephone systems with supported hardware installed including a link between a Novell NetWare file server and a telephone switchbox (PBX) with a supported driver for NetWare. Beginning with this issue of Bullets, "TeleTips" will contain tips, tricks and answers to common questions or issues regarding NetWare Telephony from an administrative point of view as well as a programming point of view.

All of the TeleTips may not appear in Bullets. If you notice you are missing any (they will be numbered consecutively, beginning with TeleTip #1) you can get them from our fax service or from CompuServe.

Cross-Dressed diskettes

The Telephony Services SDK has two diskettes that are mislabeled. They contain correct information, but they have each others' labels. These diskettes are TSRVDSK1 and TSRVDSK2.
Tip: When you need the diskette TSRVDSK1 insert the TSRVDSK2 diskette and vice-versa.

TeleTip #2

Where's the Code?

Use the sample program in Figure 14 on pages 9, 10 and 11 to open a stream and make a call. Future Telephony Services API (TSAPI) sample programs will be written to this same coding style to make it easier to read the comments and the code. After all, we were hired as engineers, not literature majors.
Tip: Use the code in Figure 14 as a template for making telephony programs. It contains the framework to which other function calls can be added. Figure 14: Sample telephony program
/**************************************************
**   Include headers, macros, function prototypes, etc.
/*-------------------------------------------------
     **   ANSI
     */
     #include 
     #include 

     /*-------------------------------------------------
     **   Windows
     */
     #include 

     /*-------------------------------------------------
     **   Telephony
     */
     #include 
     #include 

/**************************************************
**   This function is the entire program; it is very
**   simple.
**   Prompt user for input, open a stream, make a
**   call and close the stream.
*/
void main(void)
{
     /*--------------------------------------------------
     The following are defined for the first call, acsOpenStream
     */
ACSHandle_t         acsHandle;
InvokeIDType_t      invokeIDType;
InvokeID_t               invokeID;
StreamType_t        streamType;
ServerID_t               serverID;
LoginID_t           loginID;
Passwd_t            passwd;
AppName_t           applicationName;
Level_t                  acsLevelReq;
Version_t           apiVer;
unsigned short      sendQSize;
unsigned short      sendExtraBufs;
unsigned short      recvQSize;
unsigned short      recvExtraBufs;
PrivateData_t       *privateData;
RetCode_t           rCode;
     /*---------------------------------------------------
     **The following are additional variables necessary for
     **acsGetEventBlock
     */
CSTAEvent_t                   eventBuffer;
unsigned short      eventBufferSize;
unsigned short      numEvents;
/*-------------------------------------------------
**The following are for the cstaMakeCall
*/
DeviceID_t                         caller,callee;
/*-------------------------------------------------
**Miscellaneous variables
*/
short done=0;

/*-------------------------------------------------
**Setup parameters for call to open stream. Also prompt user for
**input.
*/
invokeIDType=LIB_GEN_ID;
invokeID=0;                   /*don't need it, but set to zero anyway*/
streamType=ST_CSTA;           /*want to use csta functions*/

strcpy(serverID,"ATT#G3_SWITCH#CSTA#PRV-NMS");

printf("\nEnter your user name:");
scanf("%s",loginID);
printf("\nEnter your password:");
scanf("%s",passwd);
printf("\nEnter your extension:");
scanf("%s",caller);
printf("\nEnter the extension you want to call:");
scanf("%s",callee);

strcpy(applicationName,"Simple App");
acsLevelReq=ACS_LEVEL1;
strcpy(apiVer,CSTA_API_VERSION);
sendQSize=0;             /*default size queue*/
sendExtraBufs=0;         /*use default number*/
recvQSize=0;             /*use default size*/
recvExtraBufs=0;         /*use default number*/
privateData=NULL;   /*no private data*/
/*-------------------------------------------------
**Open the stream with above parameters
*/
rCode=acsOpenStream(&acsHandle,invokeIDType,invokeID,streamType,
serverID,loginID,passwd,applicationName,acsLevelReq,
          apiVer,sendQSize,sendExtraBufs,recvQSiz,recvExtraBufs,
          privateData);

if (rCode < 0)
{
     printf("acsOpenStream failure...");
     return;
}
else
{
     printf("acsOpenStream success\n");
     invokeID=rCode;
}
/*-------------------------------------------------
**Block until the confirmation has been received that the stream
**was successfully opened. Just because NetWare returned the
**function code doesn't mean the stream has been opened yet.
*/
eventBufferSize=sizeof(CSTAEvent_t);
rCode=acsGetEventBlock(acsHandle,&eventBuffer,&eventBufferSize,
          privateData,&numEvents);
if(rCode==ACSPOSITIVE_ACK)
{
     if(eventBuffer.eventHeader.eventType == ACS_OPEN_STREAM_CONF)
     {
          printf("ACS_OPEN_STREAM_CONF message has been received\n");
     }
     else
     {
          printf("event type is incorrect...");
          return;
     }
}
else
{
     printf("acsGetEventBlock failure...");
     return;
}

/*-------------------------------------------------
**Now that the stream has been successfully opened,go ahead and
**issue the make call function.
*/
rCode=cstaMakeCall(acsHandle,invokeID,caller,callee,
privateData);

/*--------------------------------------------------
**Now we need to poll for events until a confirmation has been
**received that the PBX has been able to make the call. Note
**that if something is invalid, the program will enter an
**infinite loop, as this simple program just sits and waits
**until a confirmation returns that is successful.
*/
while (!done)
{
     rCode=acsGetEventPoll(acsHandle,&eventBuffer,&eventBufferSize,
               privateData,&numEvents);

     if(rCode==ACSPOSITIVE_ACK)
     {
          if(eventBuffer.eventHeader.eventType == CSTA_MAKE_CALL_CONF)
          {
               printf("CSTA_MAKE_CALL_CONF message has been received\n");
                    done=1;
          }
               else
               {
                    printf("event type is incorrect...");
               }
               }
     }
/*-------------------------------------------------
**All done! Time to close the stream now.
*/
rCode=acsCloseStream(acsHandle,invokeID,privateData);

if (rCode < 0)
{
     printf("acsCloseStream failure...");
     return;
}
else
{
     printf("acsCloseStream success\n");
}
return;
}

TeleTip #3

Don't Walk Through a Closed Door

It seems simple enough, doesn't it? It's the same concept when programming for NetWare Telephony: you have to open the stream for Telephony to function. An acsStream is the most crucial piece of information to a telephony program. It is your door to the Telephony Server (TSERVer). Almost every function provided by the Telephony Services API (TSAPI--I say "tee-sappy") requires that you have an open stream, passed as a parameter to the function.

To open the stream, a program calls acsOpenStream(), which is passed several parameters regarding the type of stream the program wishes to open. The TSERVer returns a completion code to your program. However, this doesn't mean that the stream has been successfully opened. Two components are involved in TSAPI programming.

The first component is the TSERVer, which returns the completion code as a return value in TSAPI function calls. This code tells whether or not the TSERVer was able to accept your function call.

The second component of TSAPI is the telephone switch box (PBX) driver. It handles many of the API requests. To know when the PBX driver has performed an action, Events are passed to a program. These events come in many shapes and sizes (I suggest printing out the .H header files to become familiar with the overwhelming amount of structures) and can be either "solicited" or "unsolicited," depending on whether or not your program specifically requested them.

Receiving Confirmation Events

The most important events for us at this time are ConfirmationEvents. They tell the program if the service requested by the function call was completed correctly. Our program doesn't know when to expect these events to come back. They could return immediately, or the PBX may have to do some processing and return to our program shortly.

As a human, I don't notice a difference in the delay, but I guess my computers are more picky regarding "immediate" and "delay." Because I have to cater to my computer when I program, I guess it is important to consider the confirmation events receiving time. For example, I may have one function call that needs to be complete before others can be made. In this case my program needs to pause and wait to receive the confirmation event from that function call.

In future Teletips we will discuss four methods of receiving confirmation. Look for it on the fax server, CompuServe, future issues of Bullets or call 1-800-NETWARE for technical support.

Now that you have a little background about events, let's think about the acsOpenStream function call. If the stream has to be open before any other TSAPI calls can be made, but you don't know how long it will take to receive the confirmation event, how long should you pause your program before attempting to make other calls? If you use the acsGetEventBlock() function, your program will pause until a confirmation event is received. Since the first event that can be received is guaranteed to be an openStream confirmation event (type ACS_OPEN_STREAM_CONF), your program will pause until the stream has been opened. The only other type of event that can be received at this point in the program will indicate that the stream was not able to be opened, and your program cannot proceed to make other TSAPI calls.
Tip: By "blocking" or using the acsGetEventBlock() function after you try to open a stream with acsOpenStream, you can make sure your door is open before trying to walk through it.

Teletip #4

Did You Check All the Books?

As I was writing my first program to do conference calls, I found a call function listed in the TSAPI programming guide, cstaMakeConsultationCall(), which would put a call that has already been connected on hold and then make the second call. This is the equivalent of first using cstaHoldCall(), and then cstaMakeCall(). I thought I was set! So I got my program written, compiling and running. But the events coming back weren't correct for doing the cstaMakeConsultationCall(). In fact, when I would run the program, nine times out of ten the machine would lock up--not cool!

After a little time on my part, I decided to look in the DEFINITY System Programmer's Guide, where I probably should have started in the first place. I couldn't find the csatMakeConsultationCall() function documented anywhere. It turns out that the driver doesn't support this call. So I had to program the equivalent of the cstaMakeConsultationCall() myself, first placing the already connected call on hold, and then making a second call.

The bottom line is this: if I would have checked the DEFINITY System Programmer's Guide first, I would have saved myself a lot of time.
Tip: Though the TSAPI programmer's guide lists the functions provided by TSERVer, it is important to use the programmer's guide for your specific PBX as the reference of what is supported by your driver. Just because TSAPI provides it doesn't mean the service is available through your driver.

© 1994 Novell, Inc. All rights reserved. Novell, the N design, NetWare, DR DOS, Btrieve, XQL and LANalyzer are registered trademarks; LAN WorkShop, NetWare SFT III, NetWare Loadable Module, NLM, Global MHS, NetWare MHS, NetWare System Calls for DOS, NetWare Runtime, NetWare SQL, NetWare Btrieve, Report Executive, NetWare Asynchronous Services Interface (NASI), NetWare Management System, Xtrieve PLUS, Novell Labs, UnixWare, AppWare, AppWare Foundation, ALM, Visual AppBuilder, IPX, and MacIPX are trademarks; and NetWire and Professional Developers' Program are service marks of Novell, Inc. IBM and OS/2 are registered trademarks, and NetBIOS and SAA are trademarks of International Business Machines Corporation. Microsoft is a registered trademark and Windows and Visual Basic are trademarks of Microsoft Corporation. Macintosh is a registered trademark of Apple Computer, Inc. CompuServe is a registered trademark of CompuServe Corporation. NFS is a registered trademark of Sun Microsystems, Inc. UNIX is a trademark of UNIX Systems Laboratories, Inc. in the USA and other countries. UNIX Systems Laboratories is a wholly-owned subsidiary of Novell, Inc. WATCOM is a registered trademarks of WATCOM Systems, Inc. Novell, Inc. makes no representations or warranties with respect to any NetWare software and specifically disclaims any express or implied warranties of merchantability, title or fitness for a particular purpose. Distribution of any NetWare software is forbidden without the express written consent of Novell, Inc. Further, Novell reserves the right to discontinue distribution of any NetWare software. Novell is not responsible for lost profits or revenue, loss of use of the software, loss of data, costs of re-creating lost data, the cost of any substitute equipment or program or claims by any party other than you. Novell strongly recommends you make a backup before any software is installed. Technical support for this software may be provided at the discretion of Novell.


NOVELL PROFESSIONAL DEVELOPERS' PROGRAM

How to Become One of Our Developers

Developing computing systems is a complex, time-consuming and expensive task. Novell understands this and is committed to its developer partners. The Novell Professional Developers' Program allows you, our developer, to access our broad base of 40 million NetWare users to develop and market your products.

This program is designed for a wide range of developers who design and create commercially available solutions. This includes commercial developers, called Independent Software Vendors (ISVs), and vertical application developers who create applications for specialized markets such as manufacturing, medicine and law.

Key Features

Members of the Novell Professional Developers' Program receive the following benefits.
  • Co-Marketing Support
    Members can participate in the YES Program, which offers a variety of co-marketing opportunities as well as ongoing information about Novell's direction. The ultimate goal of the YES Program is to make it easy for customers to identify and purchase products that are optimized for Novell platforms.
  • Technical Support
    To obtain product information and technical support, phone 1-800-RED-WORD (1-800-733-9673) or 1-801-429-5281.
  • Skills Transfer
    Members may participate in the Skills Transfer Workshops conducted by a Novell specialist. The workshops offer cutting-edge training on solution design, development and implementation. Members may also attend Novell Compass Special Interest Groups, where they have the chance to review products and provide feedback directly to Novell development teams.
  • Project/Opportunity Services
    Members have access to Novell expertise through the developer forums on CompuServe. These forums address developer issues including technical information and support for Novell products and development tools.
  • Information Services
    As a developer, you receive Novell Developer Notes, a publication targeted at network software developers. Other publications are also available: Bullets, a monthly technical journal; Appnotes (subscription only), a technical journal for network design; and the annual Developer Guide to Programs, Products, and Services. Members also get access to Novell's NDEVSUP CompuServe forum_an electronic meeting place where developers can exchange information with each other and with Novell staff members.
  • No Program Fees
    Membership in this program is free of charge and open to all developers. If you would like further information about the Professional Developers' Program or would like to apply for membership, please phone 1-800-RED-WORD (1-800-733-9673) or 1-801-429-5281. If you would like to order Novell development tools, please call 1-800-RED-WORD. You may also contact the program administrator by E-mail at the following address: devprog@novell.com.

FROM THE COCKPIT

Boy--if one thing's certain in the computer industry, it's change (sorry about the cliche). Organizations change shape, new names appear and through it all we hope that we don't break what works while improving what doesn't work so well.

Why isn't Mad Poarch writing this column? Novell has experienced some significant changes over the past several months. First, we have completed the spin-off of the Btrieve and NetWare SQL technologies to a newly formed company, Btrieve Technologies, Inc. in Austin, Texas. Quite a few of Novell's Austin-based employees have become part of the BTI Developer Support organization including the former Director of Developer Support, Mad Poarch. Novell wishes them the very best!

We have relocated the Developer Support function as well as Developer Programs from Austin, Texas to Provo, Utah. As the new head of the Developer Support group, I want to share a few of my thoughts about our new organization and what you can expect of us in the future.

Of course, the BTI spin-off has not only affected Novell internally, but has also had an effect on our ability to be responsive to you, our development partner. During the past several months we have re-established the expertise lost in the spin-off. We are now prepared to support users of our SDKs and toolkits, including the new Telephony technology, AppWare Foundation, UnixWare and of course our traditional client and server APIs.

BTI is now the sole source of support for Btrieve products and development tools, Xtrieve and SQL. Call BTI at 1-800-BTRIEVE for customer support of these database products. With the formation of BTI and the completed transfer of the Btrieve technologies to BTI, Novell's Developer Support organization is now concentrating on supporting the Novell APIs as delivered in SDK form. We have many ways you can contact us, including a newly enabled e-mail mechanism:

     Voice:    1-800-NETWARE
          (or 1-801-429-5588)
     CompuServe/NetWire: GONetWire, Developer Support Forum
     -or- Post directly to
     Novell DevSup @ 76701,171
     Fax: 1-801-429-2990
     E-mail: DEVSUP@NOVELL (MHS)
     DevSup@Novell.com (SMTP)
     FaxBack Info:  1-800-NETWARE
          (or 1-801-429-5588)
          1-800-RED-WORD
Our support organization is also the designated point of contact for the assignment and registration of various software IDs used by our developers. These software IDs include Server Type numbers, IPX socket IDs, VLM IDs, Directory Services Schema Classes and Objects. To register call our administrator at 1-801-429-3101.

You will notice that this issue is number 4 even though it is the September issue. With the Austin-to-Provo transition, we saw four months pass without producing an issue. Now that the transition is complete, you can expect to see regular, monthly publication of future issues of Bullets.

Many of us are new to this effort, but you will find that we're excited to work with you. We believe our opportunity for growth with you is vast and encouraging. In addition, we will be a strong and supportive advocate for your needs to the rest of the Novell organization. Jared Blaser Director Developer Support/Services


DEVELOPER EDUCATION

Available Novell Developer Education Courses

Novell Developer Education offers several courses for developers who use Novell's development tools.
930 - Developing NetWare Loadable Modules  (NLMs)
940 - NetWare Programming: Basic Services
941 - Directory Services
945 - NetWare Programming: Protocol Support
950 - Visual AppBuilder
954 - -ALM Development
958 - The AppWare Foundation
To obtain information on pricing, location, scheduling and course content for classes held in the US, call 1-800-233-3382, 1-801-429-5508 or 1-800-NETWARE. For information on classes outside of the US, contact your local Novell office.

CONTACTING NOVELL

Developer Support

Developers in the U.S. and Canada may contact Novell Developer Support via telephone, fax, BBS or electronic mail via CompuServe, MHS or the Internet.

Voice

For both presales and postsales support, call Novell Developer Support between 8:00 a.m. and 5:00 p.m. Mountain Time at 1-801-429-5588. Many calls to Novell Developer Support are passed to a software support engineer immediately. Calls to Novell Developer Support generally will be acknowledged or answered within four hours.

Fax

If you prefer, you may contact Novell Developer Support via fax at 1-801-429-2990. Faxed questions are acknowledged or answered within 24 hours.

Developer BBS

If you do not have access to either CompuServe or the Internet, send test cases to our BBS. Set your communication software to N-8-1 and call 1-801-429-5836.

E-mail: CompuServe

Post your messages in the appropriate section addressed to Novell at 76701,171. These messages will receive a response within 24 hours.

E-mail: MHS

You may direct your questions and comments to Novell Developer Support via Novell's Message Handling Service E-mail facility. Address your messages to devsup@novell. These messages will receive a response within 24 hours.

E-mail: Internet (SMTP)

An alternative method of contacting Novell Developer Support is through the Internet E-mail system. Send your messages to devsup@novell.com. These messages will receive a response within 24 hours.

NetWire on CompuServe

Novell's NetWire forum is open to all registered CompuServe subscribers. Through the NDEVSUP forum, professional developers writing applications with Novell development tools can gain access to information specific to Novell development. Support, patches, periodicals and product information, as well as information on all of the programs and services provided for Novell developers are accessible through this forum. Post your messages in the appropriate section addressed to Novell at 76701,171. Technical questions will be acknowledged or answered by Novell Developer Support within 24 hours.

Novell Products and SDKs

Novell products on the "Currently Shipping Developer Products" list (see page 15 of this issue), including the Red Box Products, are available to Novell Professional Developer's Program members. Call 1-800-RED-WORD (1-800-733-9673) or 1-303-894-4135 to order these products or to receive additional information. To order other Red Box Products not listed, contact your local Novell office or Novell Authorized Reseller.

Novell Labs

For information on Novell Labs development tools, education classes and product certification, in the U.S. and Canada call 1-800-453-1267 ext. 5544 or 1-801-429-5544, or call your local Novell office (see back cover of this issue).

Novell Developer Relations

Novell Professional Developers or those wishing to become members may contact Novell Developer Relations via telephone, fax, or electronic mail via Compuserve, MHS or the Internet.

Voice

For general information or questions on Novell Developer Relations programs, in the U.S. or Canada call 1-800-RED-WORD (1-800-733-9673). All others call 1-801-429-5281.

Fax

If you prefer, you may contact Novell Developer Relations via fax at 1-801-429-7207.

NetWire on CompuServe

Novell's NetWire forum is open to all registered Compuserve subscribers. Through the NDEVREL forum, Novell Professional Developer's Program-related issues or general questions may be posted. Through the NDEVINFO forum, customers who do not have products may post pre-sales product information questions on all Novell SDKs.

E-mail: MHS or Internet (SMTP)

You may direct your questions and comments to Novell Developer Relations via Novell's Message Handling Service E-mail facility. Address your messages to devprog@novell.com. Use the same address when going through the Internet E-mail system.