PMDF popstore & MessageStore Manager's Guide


Previous Next Contents Index


Chapter 12
Application Program Interface (API)

The popstore provides an application program interface (API). With this interface, sites can write their own code to directly create, manipulate, and delete user accounts as well as interface the popstore to billing utilities and other management interfaces.

12.1 Fundamentals

The popstore API is a re-entrant, thread-safe API. User and message contexts are shared between API client code and the API so as to facilitate the handling of multiple accounts and messages simultaneously from either single or multi-threaded programs. Note that writers of multi-threaded API client code should read Section 12.9.

Access to the underlying profile and message files is controlled and coordinated by the API subroutines. Programs must not attempt to access those files directly. The contexts used by the API are not opaque: clients of the API are provided with structure definitions for those contexts and can view the individual data fields in them. However, these fields must be treated as read only data and must not be changed. Indeed, changes to them generally will not affect the actual on-disk data. To change the actual, underlying on-disk data, call the appropriate API subroutines to effect the desired change.

For C programmers, a C header file declaring basic constants, data types, structures, and API subroutines in provided. This header file is the popstore.h header file and is, on UNIX and NT platforms, located in the /pmdf/include/ directory. On OpenVMS platforms, it is located in the PMDF_COM: directory.

In order to use the popstore API, you must first call the POPSTORE_init subroutine so as to initialize the API. When finished with the API, be sure to call POPSTORE_end. The sections 12.2--12.8 provide information and code examples for performing common tasks. Section 12.12 provides complete descriptions for each API subroutine. See Section 12.10 for information on linking programs against the API.

12.2 Creating Accounts

There are two approaches to creating accounts: either create an account from scratch with no default settings for fields in the account's profile, or create the account by copying fields from another account profile and then subsequently changing desired fields in the new account. Either approach is acceptable; both methods are described below. The advantage to the latter approach is that by copying the default account, the site's default account settings are used as an initial basis for the new account.

12.2.1 From Scratch

The subroutines POPSTORE_user_create_set and POPSTORE_user_create are used to create an account from scratch. With a variable of type


POPSTORE_user_context *user_context 
initialized to NULL, make successive calls to POPSTORE_user_create_set to set values for the account to be created. The username field must be set, and it is always a good idea to set a password too unless you genuinely want the account to require no password to access it. After setting the desired fields, call POPSTORE_user_create to actually create the account and dispose of the context created by the first call to POPSTORE_user_create_set. That call will write to disk the profile file for the account and create an entry in the user database. If the username for the account conflicts with another existing account, the account will not be created and a POPSTORE_USEREXISTS error will be returned.

Note that the POPSTORE_user_create_set subroutine will not allow the MANAGE usage flag to be set or cleared without first calling POPSTORE_manage to explicitly authorize such actions. (cleared). Note further that regardless of any value set for the last billing field, that field will be set to the current date and time when POPSTORE_user_create is called.

An example program which creates the profile


# pmdf popstore show joe
Username:           joe 
Owner:              Joe User 
Group:              staff 
Store Type:         popstore 
Usage flags: 
Site-defined: 
 
Last pwd change:    No time recorded 
Last connect:       No time recorded 
Last disconnect:    No time recorded 
Total connect time: 0 00:00:00 
Total connections:  0 
Past block days:    0 
Last billing:       Tue Nov 19 10:25:18 2012 
 
Message count:              0 (0 total messages received) 
Quota used:              0.00 Kbytes 
Primary quota:          90.00 Kbytes 
Overdraft quota:        10.00 Kbytes 
is shown in Example 12-1. The following items of note are identified with callouts in the sample program:

  1. check is a subroutine used to check the return status from each call to the popstore API. In the event of an error, an error message is output, the API shutdown, and the program exited.
  2. Before making any other API calls, the API is first initialized with a call to POPSTORE_initialize.
  3. Values for fields in the structure are set as desired.
  4. The account is created with a call to POPSTORE_user_add.
  5. Finally, the API is shutdown.

Example 12-1 Creating a New Account from Scratch

/****************************************************************** 
 *                                                                * 
 *  create_sample.c                                               * 
 *  Sample subroutine to create a popstore account from scratch.  * 
 *                                                                * 
 ******************************************************************/ 
 
#include <stdio.h> 
#include <stdlib.h> 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
void check (int stat) (1)
{ 
  if (stat == POPSTORE_SUCCESS) return; 
  fprintf (stderr, "Error %d: %s\n", stat, POPSTORE_error_to_text (stat)); 
  (void) POPSTORE_end (); 
  exit (1); 
} 
 
main () 
{ 
  POPSTORE_user_context *ctx; 
 
  /* 
   *  Initialize the popstore 
   */ 
  check (POPSTORE_init (1, NULL, "create_sample", 13)); (2)
 
  /* 
   *  Set values for various fields 
   */ 
  ctx = NULL; 
  check (POPSTORE_user_create_set (&ctx, POPSTORE_SET_USERNAME, 3, "joe")); (3)
  check (POPSTORE_user_create_set (&ctx, POPSTORE_SET_GROUP_NAME, 5, "staff")); 
  check (POPSTORE_user_create_set (&ctx, POPSTORE_SET_OWNER, 10, "Joe User")); 
  check (POPSTORE_user_create_set (&ctx, POPSTORE_SET_PASSWORD, 6, "secret")); 
  check (POPSTORE_user_create_set (&ctx, POPSTORE_SET_QUOTA,     1024*90)); 
  check (POPSTORE_user_create_set (&ctx, POPSTORE_SET_OVERDRAFT, 1024*10)); 
 
  /* 
   *  Create the account 
   */ 
  check (POPSTORE_user_create (&ctx)); (4)
 
  /* 
   *  All done 
   */ 
  (void) POPSTORE_end (); (5)
} 

12.2.2 By Copying

New accounts can also be created by copying an old account with the POPSTORE_user_copy_d subroutine and then changing the value of fields with POPSTORE_user_update. For instance, both of the popstore management interfaces create new accounts by copying the default account to the new account and then changing the requested fields in the new account.

Note that the POPSTORE_user_update subroutine will not allow the MANAGE usage flag can not be set or cleared without first calling POPSTORE_manage to explicitly authorize such actions.

The code in Example 12-2 creates the account joe by first copying the default account and then changing fields in the newly created joe account with POPSTORE_user_update. The account so created is identical to that created from scratch in Example 12-1. The following items of note are identified with callouts in the example program:

  1. check is a subroutine used to check the return status from each call to the popstore API. In the event of an error, an error message is output, the API shutdown, and the program exited.
  2. A macro to help construct an item list.
  3. Before making any other API calls, the API is first initialized with a call to POPSTORE_initialize.
  4. Values for entries in the item list are set. These entries describe settings to make for fields in the new account.
  5. The new account is created. It is identical to the default account except for the username and password fields.
  6. Fields in the new account are changed to reflect the desired values for those fields.
  7. Finally, the API is shutdown.

Example 12-2 Creating a New Account by Copying the default Account

/**************************************************************** 
 *                                                              * 
 *  copy_sample.c                                               * 
 *  Sample subroutine to create a popstore account by copying   * 
 *  the default account.                                        * 
 *                                                              * 
 ****************************************************************/ 
 
#include <stdio.h> 
#include <stdlib.h> 
 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
static POPSTORE_user_context *user_context = NULL; 
 
void check (int stat) (1)
{ 
  if (stat == POPSTORE_SUCCESS) return; 
  fprintf (stderr, "Error %d: %s\n", stat, POPSTORE_error_to_text (stat)); 
  if (user_context) (void) POPSTORE_user_end (user_context); 
  (void) POPSTORE_end (); 
  exit (1); 
} 
 
#define PUSH(list,code,addr,len) \ (2)
  list[item_index].item_code      = (code); \
  list[item_index].item_address   = (addr); \
  list[item_index++].item_length  = (len); 
 
main () 
{ 
  POPSTORE_item_list item_list[5]; 
  int item_index   = 0; 
  char group[]     = "staff"; 
  char owner[]     = "Joe User"; 
  uint32 quota     = 1024*90; 
  uint32 overdraft = 1024*10; 
  char errmsg[80]; 
  int errmsg_len; 
 
  /* 
   *  Initialize the popstore 
   */ 
  check (POPSTORE_init (1, NULL, "copy_sample", 11)); (3)
 
  /* 
   *  Build an item list describing the fields to set new values for 
   */ 
  PUSH (item_list, POPSTORE_SET_GROUP_NAME, group,      strlen (group)); (4)
  PUSH (item_list, POPSTORE_SET_OWNER,      owner,      strlen (owner)); 
  PUSH (item_list, POPSTORE_SET_QUOTA,      &quota,     0); 
  PUSH (item_list, POPSTORE_SET_OVERDRAFT,  &overdraft, 0); 
  PUSH (item_list, POPSTORE_SET_END,        NULL,       0); 
 
  /* 
   *  Create the new account as a duplicate of the default account but 
   *  with the desired new username and password 
   */ 
  check (POPSTORE_user_copy_d (NULL, 0, "default", 7,  (5)
                               NULL, 0, "joe", 3, 
                               "secret", 6, 0)); 
 
  /* 
   *  Change the account settings 
   */ 
  check (POPSTORE_user_begin_d (NULL, 0, &user_context, "joe", 3, 
                                POPSTORE_NOACCOUNTING, "copy_sample", 11)); 
  check (POPSTORE_user_update (user_context, item_list,  (6)
         errmsg, &errmsg_len, sizeof(errmsg))); 
  check (POPSTORE_user_end (user_context)); 
  user_context = NULL; 
 
  /* 
   *  All done 
   */ 
  POPSTORE_end (); 
} 

12.3 Modifying Accounts

Fields in an existing account can be modified using the POPSTORE_user_update subroutine. This subroutine accepts as input a user context created by POPSTORE_user_begin_d and an item list describing the fields to change and the new values to use for those fields. Before making any changes, the validity of the entries in the item list is first determined. Only if the entries are all correct, are any changes then made. The changes are made atomically: the profile is locked, read, all changes made, written back to disk, and then unlocked. In the event of an unexpected error, the old profile data is restored if possible.

An example of using POPSTORE_user_update is given in Example 12-2. When modifying accounts, keep the following notes in mind:

  1. The username field for an account can not be changed with POPSTORE_user_update. To change that field, use POPSTORE_user_copy_d specifying a non-zero value for the do_rename argument of that subroutine.
  2. The MANAGE flag can only be set or cleared if a prior call to POPSTORE_manage has been made which enables the ability to set that bit.
  3. When changing the count of stored messages for an account, the value can only be decreased. When the count is decreased from M to the value N, then the oldest M-N messages are deleted (e.g., when M=N, all messages are deleted). Note that unread deleted messages are simply deleted: they are not returned to their originator. If they should instead be returned, use POPSTORE_message_return.
  4. When an account's past block days field is changed, the past block days remainder field is reset to zero.
  5. If just changing the account's password, consider using POPSTORE_user_pw_change_d.

12.4 Deleting Accounts

Accounts are deleted with POPSTORE_user_delete_d. When an account is deleted, any unread messages for that account can optionally be returned to their originators. Shown below is the call which would be made to delete the account jdoe, returning any unread messages to their originators:


stat = POPSTORE_user_delete_d ("jdoe", 4, 1); 

12.5 Listing Accounts

Formatted listings of accounts can be generated with the POPSTORE_format_profiles_d procedure. Note that this same functionality is provided at the command line with the POPSTORE utility; see Chapter 9 for details. In order to use POPSTORE_format_profiles_d, you must first decide upon a layout for the listing and then implement that layout with a formatting file. See the description of the POPSTORE_format_profiles_d subroutine for further details. Once a formatting file has been developed, it can then be used to format listings of user accounts. In the example code shown in Example 12-4, an actual formatting file used by the POPSTORE utility is used. That formatting file, as can be seen in Example 12-3, lists for each account the username, stored message count, and used quota.

Example 12-3 Formatting File for Account Listings

%first{                              Message  Quota used} 
%first{ Username                       Count    (kbytes)} 
%first{ ------------------------------------------------------} 
%flags_manage{ |*}%username{%-32s} %message_count{%7u}    %quota_used_k{%8.2f} 
%last{ ----------------------------------------------------------------} 
%last{*Note: privileged users are flagged with an asterisk} 

Example 12-4 Generating Account Listings

/*************************************************************** 
 *                                                             * 
 *  format_sample.c                                            * 
 *  Sample subroutine to generate an account listing.          * 
 *                                                             * 
 ***************************************************************/ 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
 
#ifdef __VMS 
#  include "PMDF_COM:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
void check (int stat) 
{ 
  if (stat == POPSTORE_SUCCESS) return; 
  fprintf (stderr, "Error %d: %s\n", stat, POPSTORE_error_to_text (stat)); 
  (void) POPSTORE_end (); 
  exit (1); 
} 
 
int output (void *ctx, char *line, int len, int eol, int literal) 
{ 
  if (!eol) printf ("%.*s", len, line); 
  else printf ("%.*s\n", len, line); 
  return (POPSTORE_SUCCESS); 
} 
 
main () 
{ 
  POPSTORE_format_element *format; 
 
  /* 
   *  Initialize the popstore 
   */ 
  check (POPSTORE_init (0, NULL, "format_sample", 13)); 
 
  /* 
   *  Read in the formatting file and get a formatting context 
   */ 
  check (POPSTORE_format_read (&format, "popmgr_profile_brief.txt", 24, 
#ifdef __VMS 
                               "PMDF_HTTP_POPSTORE:[000000]", 27)); 
#else 
                               "/pmdf/www/popstore/", 19)); 
#endif 
 
  /* 
   *  Display the profiles 
   */ 
  check (POPSTORE_format_profiles_d (format, NULL, 0, NULL, 0, NULL, 0, NULL, 
                                     NULL, output)); 
 
  /* 
   *  Dispose of the formatting context 
   */ 
  check (POPSTORE_format_dispose (format)); 
 
  /* 
   *  All done 
   */ 
  (void) POPSTORE_end (); 
} 

To generate a simple listing of accounts, the POPSTORE_user_list_d subroutine can prove sufficient. That subroutine is primarily intended for cases where a program needs to obtain one-by-one the usernames for each account. Sample code using POPSTORE_user_list_d to list all accounts and then the first account with a username starting with the letter "z" is given in Example 12-5.

Example 12-5 Simple Account Listing

/*************************************************************** 
 *                                                             * 
 *  list_sample.c                                              * 
 *  Sample subroutine to generate an account listing.          * 
 *                                                             * 
 ***************************************************************/ 
 
#include <stdio.h> 
 
#ifdef __VMS 
#  include "PMDF_COM:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
main () 
{ 
  POPSTORE_list_context *list_context; 
  int stat, userlen; 
  char user[POPSTORE_MAX_USER_LEN+1]; 
 
  /* 
   *  Initialize the popstore 
   */ 
  stat = POPSTORE_init (1, NULL, "list_sample", 11); 
  if (stat != POPSTORE_SUCCESS) exit (1); 
 
  /* 
   *  List all accounts 
   */ 
  printf ("---- Listing of all accounts ----\n"); 
  list_context = NULL; 
  stat = POPSTORE_SUCCESS; 
  while (stat == POPSTORE_SUCCESS) { 
     stat = POPSTORE_user_list_d (&list_context, "*", 1, NULL, 0, NULL, 0, 
                                  user, &userlen, POPSTORE_MAX_USER_LEN + 1); 
     if (stat == POPSTORE_SUCCESS) printf ("%s\n", user); 
  } 
 
  printf ("\n---- The first account starting with the letter \"z\" ----\n"); 
  list_context = NULL; 
  stat = POPSTORE_user_list_d (&list_context, "z*", 2, NULL, 0, NULL, 0, 
                               user, &userlen, POPSTORE_MAX_USER_LEN + 1); 
  if (stat == POPSTORE_SUCCESS) { 
     printf ("%s\n", user); 
     /* Done with this context; dispose of it now */ 
     (void) POPSTORE_user_list_abort (&list_context); 
  } 
  else printf ("**** No accounts begin with the letter \"z\" ****\n"); 
 
  /* 
   *  All done 
   */ 
  (void) POPSTORE_end (); 
} 

12.6 Billing Accounts

Sites who want to bill users for usage should use the POPSTORE_user_billing_d subroutine to perform "atomic" billing operations. That subroutine locks a user profile, extracts billing information, resets accounting fields, writes the user profile back to disk, unlocks the profile, and then returns the extracted billing information to the caller.

The billing period is the intervening time between when POPSTORE_user_billing_d was last called and the current billing time supplied to POPSTORE_user_billing_d. The time when POPSTORE_user_billing_d was last called is stored in each account's last billing profile field.1

The extracted billing information includes the total connect time and past block days of message storage used during the billing period. After that information is extracted, those two fields are set to the value zero. In addition, the last billing time fields in the profile and message list are set to the new billing time supplied to POPSTORE_user_billing_d, and this data is then written out to the on-disk profile file.

Example 12-6 shows sample code which uses POPSTORE_user_billing_d in conjunction with POPSTORE_user_list_d to bill each account whose associated username starts with the letter "a" and is in the students management group.

Example 12-6 Account Billing Operations

/*************************************************************** 
 *                                                             * 
 *  bill_sample.c                                              * 
 *  Sample subroutine to bill each popstore account.           * 
 *                                                             * 
 ***************************************************************/ 
 
#include <stdio.h> 
#include <times.h> 
 
#ifdef __VMS 
#  include "PMDF_COM:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
main () 
{ 
  time_t billing_time; 
  POPSTORE_user_data data; 
  POPSTORE_list_context *list_context; 
  int stat, stat2, userlen; 
  char user[POPSTORE_MAX_USER_LEN + 1]; 
 
  /* 
   *  Initialize the popstore 
   */ 
  stat = POPSTORE_init (1, NULL, "list_sample", 11); 
  if (stat != POPSTORE_SUCCESS) exit (1); 
 
  /* 
   *  Output a heading 
   */ 
  printf ("                                  Connect    Block\n"); 
  printf ("Username                             Time     Days\n"); 
  printf ("--------------------------------  -------  -------\n"); 
 
  /* 
   *  Now, loop over each account and bill it 
   */ 
  billing_time = time (NULL); 
  list_context = NULL; 
  do { 
     stat = POPSTORE_user_list_d (&list_context, "a", 1, NULL, 0, 
                                  "students", 8, user, &userlen, 
                                  POPSTORE_MAX_USER_LEN + 1); 
     if (stat == POPSTORE_SUCCESS) { 
        stat2 = POPSTORE_user_billing_d (NULL, 0, user, userlen, billing_time, 
                                         &data); 
        if (stat2 == POPSTORE_SUCCESS) { 
           printf ("%-32s   %7u  %7u\n", user, data.total_connect, 
                   data.past_block_days); 
        } else { 
           fprintf (stderr, "Unable to bill %.*s; error = %d\n", userlen, user, 
                    stat2); 
           fprintf (stderr, "%s\n", POPSTORE_error_to_text (stat2)); 
        } 
     } 
  } while (stat == POPSTORE_SUCCESS); 
  if (stat != POPSTORE_EOM) { 
     fprintf (stderr, "POPSTORE_user_list_d returned the error %d\n", stat); 
     fprintf (stderr, "%s\n", POPSTORE_error_to_text (stat)); 
  } 
 
  /* 
   *  All done 
   */ 
  (void) POPSTORE_end (); 
} 

Note

1 For new accounts, that field is initialized to the time at which the account was created.

12.7 Storing Messages

To store a message into the message store, enqueue it as a mail message to PMDF with the desired popstore recipients given as the message's envelope To: recipients. See the PMDF Programmer's Reference Manual for information on using the PMDF API to enqueue messages to PMDF.

12.8 Accessing Messages

A user's messages are accessed by first obtaining a user context, user_context, with POPSTORE_user_begin_d. The list of stored messages is the array of POPSTORE_message_ref structures which start at the address


user_context->messages 
and contain


user_context->profile->message_count 
array elements. For example, the following code fragment counts the number of unread messages stored for the user sue:

Example 12-7 Message Lists

int i, new_count, stat; 
POPSTORE_message_ref *msg_ptr; 
POPSTORE_user_context *user_context; 
 
...
 
stat = POPSTORE_user_begin_d (&user_context, "sue", 3, POPSTORE_NOACCOUNTING, 
                              "new message count", 17); 
new_count = 0; 
for (i = 0, msg_ptr = user_context->messages; 
     i < user_context->profile->message_count; 
     i++, msg_ptr++) 
  if (!(msg_ptr->flags & POPSTORE_MFLAGS_READ)) new_count++; 
stat = POPSTORE_user_end (user_context); 
printf ("Sue has %d new messages\n", new_count); 
 
...
 

Individual messages are accessed and manipulated with the POPSTORE_message subroutines. When accessing or manipulating a message, the message is referenced using its "message index". The first message stored for a user has message index value 1, the second index value 2, the third index value 3, and so on.

The code shown in Example 12-8 displays each new message for the user sue, marking each message as read after displaying it.

Example 12-8 Displaying New Messages

/*************************************************************** 
 *                                                             * 
 *  read_sample.c                                              * 
 *  Sample subroutine to display new messages for an account.  * 
 *                                                             * 
 ***************************************************************/ 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
void check (int stat) 
{ 
  if (stat == POPSTORE_SUCCESS) return; 
  fprintf (stderr, "Error %d: %s\n", stat, POPSTORE_error_to_text (stat)); 
  (void) POPSTORE_end (); 
  exit (1); 
} 
 
void display_message (POPSTORE_user_context *user_context, int msg_index) 
{ 
  char buffer[1024+1]; 
  int len, message_context, stat; 
 
  printf ("=========================================================\n"); 
  printf ("Message %d\n", msg_index); 
  printf ("=========================================================\n"); 
 
  if (POPSTORE_SUCCESS != 
      POPSTORE_message_begin (user_context, msg_index, &message_context, 
                              NULL, 0, NULL, 0)) return; 
  do { 
     stat = POPSTORE_message_read (message_context, buffer, 1024, &len); 
     if (stat != POPSTORE_READERROR) { 
        buffer[len] = '\0'; 
        printf ("%s", buffer); 
     } 
  } while (stat == POPSTORE_SUCCESS); 
  (void) POPSTORE_message_end (message_context); 
  printf ("=========================================================\n"); 
} 
 
main () 
{ 
  POPSTORE_message_ref *msg_ptr; 
  int i, stat; 
  POPSTORE_user_context *user_context; 
 
  /* 
   *  Initialize the popstore 
   */ 
 
  check (POPSTORE_init (1, NULL, "read_sample", 11)); 
 
  /* 
   *  Access the popstore account 
   */ 
  check (POPSTORE_user_begin_d (NULL, 0, &user_context, "sue", 3, 
                                POPSTORE_ACCOUNTING, "read_sample", 11)); 
 
  /* 
   *  Display the new messages 
   */ 
  msg_ptr = user_context->messages; 
  for (i = 0, msg_ptr = user_context->messages; 
       i < user_context->profile->message_count; 
       i++, msg_ptr++) 
    if (!(msg_ptr->flags & POPSTORE_MFLAGS_READ)) { 
       display_message (user_context, i+1); 
       (void) POPSTORE_message_mark_read (user_context, i+1); 
  } 
 
  /* 
   *  Deaccess the account 
   */ 
  (void) POPSTORE_user_end (user_context); 
 
  /* 
   *  And shut down the popstore 
   */ 
  (void) POPSTORE_end (); 
} 

12.9 Using the API from Multi-threaded Programs

Multi-threaded programs need to register mutex handling subroutines with the PMDF API subroutine PMDF_set_mutex prior to initializing either the PMDF or popstore APIs. In addition, when calling POPSTORE_initialize, supply the address of the sleep subroutine provided to PMDF_set_mutex.

12.10 Compiling and Linking Programs

OpenVMS Systems

To declare the API subroutines, data structures, and constants, C programs should use the PMDF_COM:popstore.h header file.

Linking programs to the popstore API is accomplished with a link command of the form


$ LINK program,PMDF_EXE:pmdfshr_link.opt/OPT
where program is the name of the object file to link.

Solaris Systems

To declare the API subroutines, data structures, and constants, C programs should use the /pmdf/include/popstore.h header file.

Linking a C program to the API is accomplished with a link command of the form


% cc -R/pmdf/lib/ -L/pmdf/lib/ -o program program.c \
        -lpmdf -lsocket -lintl -lnsl -lm -ldb -lldapv3
where program is the name of your program.

NT Systems

To declare the API subroutines, data structures, and constants, C programs should use the C:\pmdf\include\popstore.h header file.

When linking programs to the API with the Microsoft C/C++ compiler, use the switches


-mD -D_WIN32_WINNT=0x0400 C:\pmdf\lib\libpmdf.lib 

12.11 Basic Constants, Types, and Data Structures

Basic constants and data types used by the popstore are listed in Tables 12-1 and 12-2. The data structures describing a user profile, POPSTORE_user_data, and a message list, POPSTORE_message_list, are shown in Sections 12.11.1 and Section 12.11.2. A user context as obtained from the POPSTORE_user_begin_d subroutine, is a pointer to a POPSTORE_user_context structure and is described in Section 12.11.3. Fields in that structure point to data structures containing the user's profile and message list. All of these constants, data types, and structures are declared in the popstore.h header file located in the /pmdf/include/ directory on UNIX and NT platforms and the PMDF_COM: directory on OpenVMS.

Table 12-1 Constants
Constant Value Description
ALFA_SIZE 252 A basic PMDF string size
BIGALFA_SIZE 1024 A basic PMDF string size
POPSTORE_FLAGS_DELETE 16 Bit mask for the DELETE usage flag bit
POPSTORE_FLAGS_DISMAIL 2 Bit mask for the DISMAIL usage flag bit
POPSTORE_FLAGS_DISUSER 1 Bit mask for the DISUSER usage flag bit
POPSTORE_FLAGS_LOCKPWD 4 Bit mask for the LOCKPWD usage flag bit
POPSTORE_FLAGS_MANAGE 8 Bit mask for the MANAGE usage flag bit
POPSTORE_FULL_UIDL_LEN 23 Length in bytes of a full message UIDL derived
POPSTORE_MAX_DOMAIN_LEN 40 Maximum length in bytes of a user domain name
POPSTORE_MAX_FILE_LEN 1024 Maximum length in bytes for full file paths
POPSTORE_MAX_GROUP_LEN 16 Maximum length in bytes of a management group name
POPSTORE_MAX_OWN_LEN 40 Maximum length in bytes for the profile owner field
POPSTORE_MAX_PRIV_LEN 64 Maximum length in bytes for the profile site-defined private data field
POPSTORE_MAX_PWD_LEN 32 Maximum length in bytes for the profile password field
POPSTORE_MAX_USER_LEN 32 Maximum length in bytes for the profile username field
POPSTORE_MFLAGS_READ 1 Bit mask for the READ message flag bit
POPSTORE_MSG_FILE_FORMAT_VERSION 0 Current value for message file format version
POPSTORE_MSG_NAME_LEN 19 Length in bytes of a message file name
POPSTORE_USERDATA_VERSION 2 Current value for the profile file format version

Table 12-2 Basic Data Types
Type Size (bytes) Underlying data type
int32 4 int
ubyte 1 unsigned char
uint32 4 unsigned int
ushort 2 unsigned short int

12.11.1 POPSTORE_user_data Structure

User profile information is stored in a POPSTORE_user_data structure of the form shown below. To change user profile information, the POPSTORE_user_set or POPSTORE_user_update subroutines should be used. The former is used when creating an account---an account which does not yet exist. The latter is used to modify an existing account. The profile information for an existing account is obtained with the POPSTORE_user_begin_d subroutine. That subroutine returns a pointer to a POPSTORE_user_context structure; the profile data is pointed at by the profile field in that structure.

The layout of the POPSTORE_user_data structure is shown below:


typedef struct { 
  ubyte  version; 
  ubyte  store_type; 
  ushort flags; 
  ubyte  ulen; 
  ubyte  plen; 
  ubyte  olen; 
  ubyte  slen; 
  char   username[POPSTORE_MAX_USER_LEN]; 
  char   password[POPSTORE_MAX_PWD_LEN]; 
  char   owner[POPSTORE_MAX_OWN_LEN]; 
  ubyte  private[POPSTORE_MAX_PRIV_LEN]; 
  uint32 quota; 
  uint32 return_after; 
  uint32 overdraft; 
  time_t last_billing; 
  uint32 total_conntections; 
  time_t last_connect; 
  time_t last_pwd_change; 
  time_t last_disconnect; 
  uint32 total_connect; 
  uint32 past_block_days; 
  uint32 past_block_days_remainder; 
  uint32 message_count; 
  uint32 quota_used; 
  uint32 received_messages; 
  uint32 received_bytes; 
  ubyte  reserved5[3]; 
  ubyte  glen; 
  char   group[POPSTORE_MAX_GROUP_LEN]; 
} POPSTORE_user_data; 
The interpretation of these fields are as follows:

version

Data structure version number. The current version number for the data structure is given by the POPSTORE_USERDATA_VERSION constant.

store_type

Type of message store used for this profile. Value will typically be zero POPSTORE_STORE_TYPE_POP.

flags

Bit masked field containing usage flag settings. The bits in this field can be tested with the POPSTORE_FLAGS_ constants.

ulen

Length in bytes of the value stored in the username field.

plen

Length in bytes of the value stored in the password field. The value of this field is encrypted.

olen

Length in bytes of the value stored in the owner field.

slen

Length in bytes of the value stored in the private field.

username

The account username. This field is not null terminated; the length of the value stored in this field is given by the value of the ulen field.

password

The account password. The value stored in this field is encrypted and is not null terminated. The encrypted value of the plen field gives the length of the value stored in this field.

owner

Account owner information. This field is not null terminated; the length of the value stored in this field is given by the value of the olen field.

private

Site-defined private data field. The length of the value stored in this field is given by the value of the slen field. This field is not null terminated.

quota

Primary message storage quota measured in units of bytes. A value of zero for this field conveys unlimited storage quota.

return_after

Field reserved for future use.

overdraft

Message overdraft storage quota.

last_billing

Time of last billing as measured in seconds since 1 January 1970. This field is set to the current time when the account is first created.

total_connections

Cumulative count of connections made to the account since either the account was created or this field last cleared.

last_connect

Time of last connection attempt as measured in seconds since 1 January 1970. This field is set for both successful and unsuccessful login attempts. The time is recorded when the user context is created with POPSTORE_user_begin_d and written to the profile when the context is disposed of with POPSTORE_user_end.

last_pwd_change

Time of last password change as measured in seconds since 1 January 1970. If the value is 0, then the account is pre-expired. This field is set whenever the password is successfully changed, or when the account is set to pre-expired or not pre-expired through the web-based management interface or the command line management utility.

last_disconnect

Time of last disconnect as measured in seconds since 1 January 1970. This field is set for both successful and unsuccessful login attempts. The time is recorded when the user context is disposed of with POPSTORE_user_end.

total_connect

Total number of seconds spent connected since the account was created or this field last cleared.

past_block_days

Cumulative block days for previously stored and since deleted or returned messages since the account was created or this field last cleared. The value of this field does not take into account messages currently held in the store.

past_block_days_remainder

Remainder field used in computation of block days. This field is measured in units of byte seconds.

message_count

Count of messages currently stored for the account.

quota_used

Number of bytes currently being consumed to store messages for the account. This value only takes into consideration the size of the underlying messages themselves and not the size of the actual container files.

received_messages

Cumulative count of messages received and stored for the account since either the account was created or this field last cleared.

received_bytes

Cumulative count of message bytes received and stored for the account since either the account was created or this field last cleared.

reserved5

Field reserved for future use.

glen

Length in bytes of the value stored in the group field.

group

Name of the management group to which this account belongs.

12.11.2 POPSTORE_message_ref Structure

A user's list of stored messages is stored as an array of zero or more array elements each of type POPSTORE_message_ref. To change information in the list (e.g., mark messages for deletion), use the appropriate POPSTORE_message_ subroutine. The list of an account's stored messages is obtained with the POPSTORE_user_begin_d subroutine. That subroutine returns a pointer to a POPSTORE_user_context structure; the message list is pointed at by the messages field in that structure. The count of stored messages, and hence the count of array elements in the message list, is given by the user profile information also available from the user context structure. See, for instance, Example 12-7.

The layout of the POPSTORE_message_ref structure is shown below:


typedef struct { 
  uint32 size; 
  uint32 last_billing; 
  time_t created; 
  uint32 flags; 
  char   uidl[4]; 
  char   filename[POPSTORE_MSG_NAME_LEN]; 
  ubyte  pad; 
} POPSTORE_message_ref; 
The interpretation of these fields are as follows:

size

Size in bytes of the message. This size includes CRLF terminators but does not include any dots used for dot stuffing.

last_billing

Time at which usage billing was last done for the storage of this message. Measured as the count of seconds since 1 January 1970.

created

Time at which the message file was created. Measured as the count of seconds since 1 January 1970.

flags

Bit masked field containing message status flag bits. The bits in this field can be tested with the POPSTORE_MFLAGS_ constants. Currently, only one flag bit is stored in the message list: the read/unread bit accessed with the POPSTORE_MFLAGS_READ bit mask.

uidl

The message UIDL begins with this field and includes the filename field. The length in bytes of the UIDL is given by POPSTORE_FULL_UIDL_LEN. This portion of the UIDL is unique for each recipient of the underlying message file.

filename

This field forms part of the message UIDL and is the same for all popstore recipients of this particular message. This field also is the name of the underlying file containing the message.

pad

A padding byte. The value of this byte is set to zero thus making the full UIDL accessible as a null terminated string.

12.11.3 POPSTORE_user_context Structure

Information about a popstore account is returned to callers of POPSTORE_user_begin_d in the form of a pointer to a structure of type POPSTORE_user_context---a "user context". Fields in this structure must not be changed; use the appropriate API subroutines to effect the needed changes. When through with a user context, call POPSTORE_user_end to dispose of the context. Note that it is important that that call be made: not only does it dispose of allocated resources, it also updates accounting information for the account and performs any requested message deletion operations.

The layout of the POPSTORE_user_context structure is shown below:


typedef struct { 
  time_t                connect; 
  uint32                log_subid; 
  int                   do_accounting; 
  uint32                block_days; 
  uint32                block_days_remainder; 
  POPSTORE_user_data   *profile; 
  POPSTORE_message_ref *messages; 
  POPSTORE_string       filespec; 
  char                  pad[3]; 
  POPSTORE_userdb_data *userdb_data; 
  void                 *reserved0; 
  char                  domain[POPSTORE_MAX_DOMAIN_LEN]; 
  int                   dlen; 
} POPSTORE_user_context; 
The interpretation of these fields are as follows:

connect

Time at which this context was established.

log_subid

Sub-identifier used for logging purposes.

do_accounting

Flag indicating whether or not accounting should be done for this context.

block_days

Accumulated block days for messages deleted with this context.

block_days_remainder

Accumulated block days roundoff for messages deleted with this context.

profile

The user's profile data. The value of this field is a pointer to the profile information for this user account.

messages

The user's list of stored messages. The value of this field is a pointer to an array of POPSTORE_message_ref elements. This array contains profile->message_count elements.

filespec

File specification for the underlying profile file.

pad

Alignment padding bytes.

userdb_data

This field will usually be NULL. It is a pointer to the account's user database record. That record is only obtained when the popstore is performing management operations and even then only seldom.

reserved0

Field reserved for future use.

domain

User domain associated with this account.

dlen

Length in bytes of the user domain associated with this account. A length of zero indicates the default domain.

12.12 Subroutine Descriptions

This section documents the individual popstore API subroutines. A brief description of each subroutine is given in Table 12-3 below.

Table 12-3 Subroutines included in the API
Subroutine name Description
POPSTORE_command Obsolete: use the POPSTORE_command_d subroutine
POPSTORE_command_d Process a management command
POPSTORE_end End usage of the API
POPSTORE_error_to_text Convert a numerical error to a textual error message
POPSTORE_format_counters Format PMDF channel counter information
POPSTORE_format_dispose Dispose of a formatting context
POPSTORE_format_forwarding Obsolete: use the POPSTORE_format_forwarding_d subroutine
POPSTORE_format_forwarding_d Format forwarding information
POPSTORE_format_message Format a stored message
POPSTORE_format_messages Format a user's list of stored messages
POPSTORE_format_profile Format a user profile
POPSTORE_format_profiles Obsolete: use the POPSTORE_format_profiles_d subroutine
POPSTORE_format_profiles_d Format a list of user profiles
POPSTORE_format_read Read and parse a formatting file
POPSTORE_init Initialize the API
POPSTORE_manage Allow changing of the MANAGE usage flag
POPSTORE_message_begin Access a stored message
POPSTORE_message_end Deaccess a stored message
POPSTORE_message_mark_delete Mark a user's message copy for deletion
POPSTORE_message_mark_nodelete Mark a user's message to be retained
POPSTORE_message_mark_noread Mark a user's message as being unread
POPSTORE_message_mark_read Mark a user's message as read
POPSTORE_message_read Sequentially read a message
POPSTORE_message_return Return a message to its originator
POPSTORE_user_begin Obsolete: use the POPSTORE_user_begin_d subroutine
POPSTORE_user_begin_d Access a user account
POPSTORE_user_billing Obsolete: use the POPSTORE_user_billing_d subroutine
POPSTORE_user_billing_d Perform billing operations
POPSTORE_user_copy Obsolete: use the POPSTORE_user_copy_d subroutine
POPSTORE_user_copy_d Copy or rename an existing account
POPSTORE_user_create Create a new account
POPSTORE_user_create_dispose Abort creating a new account
POPSTORE_user_create_set Set the value of a field for an account to be created with POPSTORE_user_create
POPSTORE_user_delete Obsolete: use the POPSTORE_user_delete_d subroutine
POPSTORE_user_delete_d Delete a user account
POPSTORE_user_end Deaccess a user account
POPSTORE_user_exists Obsolete: use the POPOPSTORE_user_exists_d subroutine
POPSTORE_user_exists_d See if a username specifies a valid account
POPSTORE_user_list Obsolete: use the POPSTORE_user_list_d subroutine
POPSTORE_user_list_abort Prematurely dispose of a list
POPSTORE_user_list_d Return the usernames associated with each account within an accounting group
POPSTORE_user_pw_change Obsolete: use the POPSTORE_user_pw_change_d subroutine
POPSTORE_user_pw_change_d Change a user's password
POPSTORE_user_pw_check Perform an authentication check
POPSTORE_user_update Update a field in an existing account


Previous Next Contents Index