x400_mstutorial.c

00001 /*  Copyright (c) 2008, Isode Limited, London, England.
00002  *  All rights reserved.
00003  *                                                                       
00004  *  Acquisition and use of this software and related materials for any      
00005  *  purpose requires a written licence agreement from Isode Limited,
00006  *  or a written licence from an organisation licenced by Isode Limited
00007  *  to grant such a licence.
00008  *
00009  */
00010 
00011 /* x400_mstutorial.c 
00012  *
00013  * The purpose of this file is to simply explain how to send and receive
00014  * X400 email messages using the P7 Message store protocol.
00015  *
00016  */
00017 
00018 /*
00019  * Setting up your configuration.
00020  * Before you go any further you need to have a suitable configuration created
00021  * The simplest way to do this is to run the "quickconfig" program, and
00022  * select the "X.400" option as the configuration type.
00023  *
00024  * The "quickconfig" program is located within BINDIR. So that's typically
00025  * /opt/isode/bin on unix, and c:\Program Files\Isode\bin on Windows.
00026  *
00027  *
00028  * The purpose of this tutorial is to provide a very simple example of the 
00029  * basic principles of the Isode X.400api
00030  *
00031  * Specifically it demonstrates:
00032  * 1) The Object Oriented approach to manipulating X.400 Messages
00033  * 2) How to create a new "Session"
00034  * 3) How to create a new message associated with that session.
00035  * 4) How to add attributes to that Message.
00036  * 5) How to receive a Message.
00037  * 6) How to retrieve attributes from that Message.
00038  * 7) How to close a session.
00039  * 8) How to safely destroy a Message.
00040  *
00041  * This tutorial will only cover these basics.
00042  * the example X.400api programs give a more detailed example of how to use 
00043  * the X.400api.
00044  *
00045  *
00046  * 
00047  */
00048 
00049 #include <stdio.h>
00050 #include <stdlib.h>
00051 
00052 
00053 #include <x400_msapi.h>
00054 #include "example.h"
00055 #include <sys/types.h>
00056 #include <sys/stat.h>
00057 #include <fcntl.h>
00058 #include <errno.h>
00059 #include <time.h>
00060 
00061 /* You will need to change these two #defines to the correct values for your
00062  * system */
00063 #define HOSTNAME "dhcp-164"
00064 #define FQ_HOSTNAME HOSTNAME".isode.net"
00065 
00066 char *orig = "/CN=P7User1/OU=Sales/O="HOSTNAME"/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
00067 char *recip = "/CN=P7User2/OU=Sales/O="HOSTNAME"/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
00068 char *ms_pa = "\"3001\"/Internet="FQ_HOSTNAME"+3001"; /*Message Store presentation address */
00069 
00070 char *password = "secret"; /* password used to bind to the store */
00071 
00072 static void send_hello_world(
00073         struct X400msSession *sp
00074 );
00075 
00076 static void receive_msgs(
00077     struct X400msSession *sp,
00078     int nummsg
00079 );
00080 
00081 int main () 
00082 {
00083   int status;
00084   struct X400msSession *sp; /* This is the session pointer object.
00085                              * All subsequent objects like message objects
00086                              * are associated back to this session 
00087                              * When the session is closed these objects are 
00088                              * free'd.
00089                              */
00090   int contype = 0; /* We are using P7 - connecting to the P7 Message store */
00091   char *def_dn= "cn=foobar,c=gb";
00092 
00093   int nummsg = 0;
00094   
00095   /* Open a new session, and check that the session has been opened ok.
00096    * The different values the API can return are in x400_att.h */
00097   
00098   status = X400msOpen (contype, orig, def_dn, password, ms_pa, &nummsg, &sp);
00099   if ( status != X400_E_NOERROR ) {
00100       fprintf (stderr, "Error in Open: %s\n", X400msError (status));
00101       exit (status);
00102   }
00103   
00104   /* We now want to configure logging
00105    * Isode logging is configured using a specific XML file.
00106    * a GUI editor SBINDIR/logconfig allows you to easily alter the XML file.
00107    *
00108    * To specify a particular xml file, we need to manipulate the
00109    * session object.
00110    *
00111    * To do this we call X400msSetStrDefault, passing in the session
00112    * pointer, the attribute of the object we wish to manipulate 
00113    * (X400_S_LOG_CONFIGURATION_FILE), the filename, and the size in bytes
00114    * of the filename.
00115    *
00116    * Since we don't actually have the size of the filename in bytes, 
00117    * we can pass in 0 or -1 in for the size field. The underlying code will
00118    * calculate the size for us.
00119    */
00120 
00121   X400msSetStrDefault(sp, X400_S_LOG_CONFIGURATION_FILE, "x400api.xml", 0);
00122  
00123   /* The reference section of the API manual contains descriptions of
00124    * other default attributes you may set.
00125    */
00126   
00127   /* We can now attempt to send a message */
00128   send_hello_world(sp);
00129   
00130   X400msClose (sp);
00131   if ( status != X400_E_NOERROR ) {
00132     fprintf (stderr, "Error in Close: %s\n", X400msError (status));
00133     exit (status);
00134   }
00135 
00136   /* We can now attempt to receive that message
00137    * Notice we are binding as the recipient of the message
00138    */
00139 
00140   status = X400msOpen (contype, recip, def_dn, password, ms_pa, &nummsg, &sp);
00141   if ( status != X400_E_NOERROR ) {
00142       fprintf (stderr, "Error in Open: %s\n", X400msError (status));
00143       exit (status);
00144   }
00145 
00146   /* sp is obviously a session pointer
00147    * nummsgs is an int represtenting the number of messages available
00148    * for the current user
00149    */
00150   receive_msgs(sp,nummsg);
00151   
00152   X400msClose (sp);
00153   if ( status != X400_E_NOERROR ) {
00154     fprintf (stderr, "Error in Close: %s\n", X400msError (status));
00155     exit (status);
00156   }
00157   
00158   
00159   exit(0);
00160 }
00161 
00162 
00163 /*
00164  * 1) Sending a "Hello World!" email
00165  * 
00166  * You will need to know a single X.400 email addresses.
00167  * This email address needs to be routed to use the Gateway channel.
00168  * 
00169  * Fortunately quickconfig helps by providing a suitable user:
00170  * /CN=GatewayUser/OU=Sales/OU=HOSTNAME/O=GatewayMTA/PRMD=TestPRMD/ADMD=TestADMD/C=GB/
00171  * 
00172  * You should alter "HOSTNAME" to being the correct value for your 
00173  * configuration.
00174  *
00175  * The following section will show you how to send a "Hello World!" 
00176  * X.400 email througth the messag transfer API.
00177  */
00178 
00179 static void send_hello_world(
00180     struct X400msSession *sp
00181 )
00182 {
00183   int status;
00184 
00185   /* Now lets create a new message */
00186   struct X400msMessage *mp; /* This is the pointer to a message object */
00187   struct X400Recipient *rp; /* This is the pointer to a new recipient  */
00188 
00189 
00190   printf("Now sending the simple message\n");
00191   /* We now need to create a new message object, and have the new
00192    * message object associated with the session object.
00193    *
00194    * To do this we use X400mtMsgNew.
00195    */
00196   status = X400msMsgNew (sp, X400_MSG_MESSAGE, &mp);
00197   
00198   if ( status != X400_E_NOERROR ) {
00199     fprintf (stderr, "Error in MsgNew: %s\n", X400msError (status));
00200     exit (status);
00201   }
00202   
00203   /* We can now manipulate the message object */
00204   
00205   /* Add an originator. Similar concepts here,
00206    * we are manipulating the message object to add an originator address
00207    */
00208   status = X400msMsgAddStrParam (mp, X400_S_OR_ADDRESS, orig, -1);
00209     
00210   if ( status != X400_E_NOERROR ) {
00211     fprintf (stderr, "Error adding orignator: %s\n", X400msError (status));
00212     exit (status);
00213   }
00214   
00215   /* Create a new recipient object, and associate it with the message object.
00216    */
00217   status = X400msRecipNew (mp, X400_RECIP_STANDARD, &rp);
00218   if ( status != X400_E_NOERROR ) {
00219     fprintf (stderr, "Error adding recipient: %s\n", X400msError (status));
00220     exit (status);
00221   }
00222 
00223   /* We can now manipulate the recipient object and add the following:
00224    * 1) The OR address of the recipient.
00225    * Obviously this is important, otherwise the message cannot be routed.
00226    *
00227    * 2) The responsibility value 
00228    * You don't actually need to set this. However it is usefull to see
00229    * how the attributes being manipulated correspond with the standards.
00230    */
00231   status = X400msRecipAddStrParam (rp, X400_S_OR_ADDRESS, recip, -1);
00232   if ( status != X400_E_NOERROR ) {
00233     fprintf (stderr, "Error adding recipient address: %s\n", 
00234              X400msError (status));
00235     exit (status);
00236   }
00237   
00238   /* The following attribute might be slightly confusing.
00239    * The best thing to do at this point is to take a brief look 
00240    * at X.411, section 12.2.1.1.1.6, this describes the responsibility
00241    * attribute.
00242    */
00243 
00244   status = X400msRecipAddIntParam (rp, X400_N_RESPONSIBILITY, 1);
00245   if ( status != X400_E_NOERROR ) {
00246     fprintf (stderr, "Error adding recipient responsibility: %s\n", 
00247              X400msError (status));
00248     exit (status);
00249   }
00250 
00251   /* Extra envelope attributes */
00252   status = X400msMsgAddIntParam (mp, X400_N_CONTENT_TYPE, 2);
00253   if ( status != X400_E_NOERROR ) {
00254     fprintf (stderr, "Error adding Content type : %s\n", 
00255              X400msError (status));
00256     exit (status);
00257   }
00258   
00259   /* And now for the content */
00260   {
00261     char *content = "Hello World!";
00262     char *subject = "A simple test message";
00263 
00264     status = X400msMsgAddStrParam (mp,X400_T_IA5TEXT, content , -1);
00265     if ( status != X400_E_NOERROR ) {
00266       fprintf (stderr, "Error adding content : %s\n", 
00267                X400msError (status));
00268       exit (status);
00269     }
00270 
00271     status = X400msMsgAddStrParam (mp, X400_S_SUBJECT, subject, -1);
00272      if ( status != X400_E_NOERROR ) {
00273        fprintf (stderr, "Error adding subject : %s\n", 
00274                 X400msError (status));
00275        exit (status);
00276      }
00277   }
00278   
00279   /* we should now be able to send the message */
00280   status = X400msMsgSend (mp);
00281   if ( status != X400_E_NOERROR ) {
00282     fprintf (stderr, "Error in MsgSend: %s\n", X400msError (status));
00283     exit (status);
00284   }
00285   
00286   /* We can now delete the message
00287    * We pass in the message pointer, but also a "0".
00288    * The "0" means that the message will not be */
00289   status = X400msMsgDelete (mp,0); 
00290   if ( status != X400_E_NOERROR ) {
00291     fprintf (stderr, "Error in X400mtMsgDelete: %s\n", X400msError (status));
00292     exit (status);
00293   }
00294   
00295   printf("Sent message\n");
00296 }
00297 
00298 
00299 static void receive_msgs(
00300     struct X400msSession *sp,
00301     int nummsg
00302 )
00303 {
00304    
00305     struct X400msMessage *mp;
00306     struct X400Recipient *rp;
00307 
00308     int status;
00309     
00310     int type;
00311     int seqn;
00312     size_t length;
00313     char buffer[BUFSIZ];
00314     
00315     if (nummsg == 0) {
00316         printf ("no messages - waiting 60 seconds for a message to be delivered.....\n");
00317     }
00318     else {
00319         printf("%d messages waiting\n", nummsg);
00320     }
00321 
00322     /* This will add a delay, so the sent message will have sometime to get
00323      * through the system
00324      */
00325     status = X400msWait(sp, 1, &nummsg);
00326     if (status != X400_E_NOERROR) {
00327         fprintf(stderr, "Error from Wait: %s\n", X400msError(status));
00328         return;
00329     }
00330     
00331     /* Now we fetch the actual message.
00332      * to keep things simple we will only try to fetch the first message
00333      */
00334     status = X400msMsgGet(sp, 0, &mp, &type, &seqn);
00335     switch (status) {
00336     case X400_E_NOERROR:
00337         fprintf(stderr, "MsgGet successfully got message\n");
00338         break;
00339     default :
00340         fprintf(stderr, "Error from MsgGet: %s\n", X400msError(status));
00341         return;
00342     }
00343 
00344     /* Now we fetch various attrbitues.
00345      * A word of warning though:
00346      * These attributes may or may not be present in real messages.
00347      * we know exactly what attributes are avaliable in this test message.
00348      * so we will keep it simple and only bother checking these few */
00349     
00350     /* Fetch the originator */
00351     status = X400msMsgGetStrParam(mp, X400_S_OR_ADDRESS,
00352                                   buffer, sizeof buffer, &length);
00353     if (status != X400_E_NOERROR) {
00354         fprintf(stderr, "Error from MsgGetStrParam: %s\n",
00355                 X400msError(status));
00356         return;
00357     }
00358     printf("Originator: %.*s\n", (int)length, buffer);
00359     
00360     /* Fetch the Envelope recipient */
00361     status = X400msRecipGet(mp, X400_RECIP_ENVELOPE, 1, &rp);
00362     if (status == X400_E_NO_RECIP)
00363         return;
00364     
00365     if (status != X400_E_NOERROR) {
00366         fprintf(stderr, "Error from RecipGet: %s\n", X400msError(status));
00367         /* tidily close the session */
00368         status = X400msClose(sp);
00369         exit(status);
00370     }
00371     
00372     /* Now fetch the OR Address of the recipient.
00373      * We can safely assume that there is an OR Address since we created the
00374      * message.*/
00375     status = X400msRecipGetStrParam(rp, X400_S_OR_ADDRESS,
00376                                     buffer, sizeof buffer, &length);
00377     if (status != X400_E_NOERROR) {
00378         fprintf(stderr, "Error from X400msRecipGetStrParam: %s\n",
00379                 X400msError(status));
00380         return;
00381     }
00382     printf("Envelope Recipient : %.*s\n", (int)length, buffer);
00383     
00384     
00385     /* Now fetch the Content type int */
00386     status = X400msMsgGetIntParam (mp, X400_N_CONTENT_TYPE, &type);
00387     if ( status != X400_E_NOERROR ) {
00388         fprintf (stderr, "Error in X400msMsgGetIntParam content type: %s\n",
00389                  X400msError (status));
00390         return;
00391     }
00392     printf("Content type: %i\n",type);
00393 
00394     
00395     /* Now fetch the subject of the message */
00396     status = X400msMsgGetStrParam(mp, X400_S_SUBJECT,
00397                                   buffer, sizeof buffer, &length);
00398     if ( status != X400_E_NOERROR ) {
00399         fprintf (stderr, "Error in X400msMsgGetStrParam subject: %s\n",
00400                  X400msError (status));
00401         return;
00402     }
00403     
00404         printf("Subject: %.*s\n", (int)length, buffer);
00405     
00406     /* Now fetch the IA5-text content of the message.*/
00407     status = X400msMsgGetStrParam(mp, X400_T_IA5TEXT,
00408                                   buffer, sizeof buffer, &length);
00409     if ( status != X400_E_NOERROR ) {
00410         fprintf (stderr, "Error in X400msMsgGetStrParam subject: %s\n",
00411                  X400msError (status));
00412         return;
00413     }
00414 
00415     printf("Text:\n%.*s\n", (int)length, buffer);
00416     
00417     X400msMsgDelete(mp, 0);
00418 }
Copyright © 2008 Isode privacy   feedback Subscribe to our rss newsfeed