x400_mstutorial.c
1 /* Copyright (c) 2008-2010, Isode Limited, London, England.
2  * All rights reserved.
3  *
4  * Acquisition and use of this software and related materials for any
5  * purpose requires a written licence agreement from Isode Limited,
6  * or a written licence from an organisation licenced by Isode Limited
7  * to grant such a licence.
8  *
9  */
10 
11 /* x400_mstutorial.c
12  *
13  * The purpose of this file is to simply explain how to send and receive
14  * X400 email messages using the P7 Message store protocol.
15  *
16  */
17 
18 /*
19  * Setting up your configuration.
20  * Before you go any further you need to have a suitable configuration created.
21  *
22  * The purpose of this tutorial is to provide a very simple example of the
23  * basic principles of the Isode X.400api
24  *
25  * Specifically it demonstrates:
26  * 1) The Object Oriented approach to manipulating X.400 Messages
27  * 2) How to create a new "Session"
28  * 3) How to create a new message associated with that session.
29  * 4) How to add attributes to that Message.
30  * 5) How to receive a Message.
31  * 6) How to retrieve attributes from that Message.
32  * 7) How to close a session.
33  * 8) How to safely destroy a Message.
34  *
35  * This tutorial will only cover these basics.
36  * the example X.400api programs give a more detailed example of how to use
37  * the X.400api.
38  *
39  *
40  *
41  */
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 
46 
47 #include <x400_msapi.h>
48 #include "ms_example.h"
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <errno.h>
53 #include <time.h>
54 
55 /* Define IC_ATTRIBUTE
56  * For gcc/g++ this becomes __attribute__ and is used for the printf type
57  * format checking.
58  * Defined to be empty for other compilers
59  */
60 
61 #if defined(__GNUC__) || defined (__GNUG__)
62 #define IC_ATTRIBUTE(x) __attribute__ (x)
63 #else
64 #define IC_ATTRIBUTE(x)
65 #endif
66 
67 /* To annotate function parameters which are known not to be used
68  * Not in gcc/g++ prior to v4 (I think)
69  */
70 #if (defined(__GNUG__) && __GNUG__ >= 4) || (!defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 3)
71 # define ARGNOTUSED IC_ATTRIBUTE((unused))
72 #else
73 # define ARGNOTUSED
74 #endif
75 
76 /* You will need to change these two #defines to the correct values for your
77  * system */
78 #define HOSTNAME "dhcp-164"
79 #define FQ_HOSTNAME HOSTNAME".isode.net"
80 
81 char *orig = "/CN=P7User1/OU=Sales/O="HOSTNAME"/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
82 char *recip = "/CN=P7User2/OU=Sales/O="HOSTNAME"/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
83 char *ms_pa = "\"3001\"/Internet="FQ_HOSTNAME"+3001"; /*Message Store presentation address */
84 
85 char *password = "secret"; /* password used to bind to the store */
86 
87 static void send_hello_world(
88  struct X400msSession *sp
89 );
90 
91 static void receive_msgs(
92  struct X400msSession *sp,
93  int nummsg
94 );
95 
96 int main (int argc ARGNOTUSED, char ** argv ARGNOTUSED)
97 {
98  int status;
99  struct X400msSession *sp; /* This is the session pointer object.
100  * All subsequent objects like message objects
101  * are associated back to this session
102  * When the session is closed these objects are
103  * free'd.
104  */
105  int contype = 0; /* We are using P7 - connecting to the P7 Message store */
106  char *def_dn= "cn=foobar,c=gb";
107 
108  int nummsg = 0;
109 
110  /* Open a new session, and check that the session has been opened ok.
111  * The different values the API can return are in x400_att.h */
112 
113  status = X400msOpen (contype, orig, def_dn, password, ms_pa, &nummsg, &sp);
114  if ( status != X400_E_NOERROR ) {
115  fprintf (stderr, "Error in Open: %s\n", X400msError (status));
116  exit (status);
117  }
118 
119  /* We now want to configure logging
120  * Isode logging is configured using a specific XML file.
121  * a GUI editor SBINDIR/logconfig allows you to easily alter the XML file.
122  *
123  * To specify a particular xml file, we need to manipulate the
124  * session object.
125  *
126  * To do this we call X400msSetStrDefault, passing in the session
127  * pointer, the attribute of the object we wish to manipulate
128  * (X400_S_LOG_CONFIGURATION_FILE), the filename, and the size in bytes
129  * of the filename.
130  *
131  * Since we don't actually have the size of the filename in bytes,
132  * we can pass in 0 or -1 in for the size field. The underlying code will
133  * calculate the size for us.
134  */
135 
136  X400msSetStrDefault(sp, X400_S_LOG_CONFIGURATION_FILE, "x400api.xml", 0);
137 
138  /* The reference section of the API manual contains descriptions of
139  * other default attributes you may set.
140  */
141 
142  /* We can now attempt to send a message */
143  send_hello_world(sp);
144 
145  X400msClose (sp);
146  if ( status != X400_E_NOERROR ) {
147  fprintf (stderr, "Error in Close: %s\n", X400msError (status));
148  exit (status);
149  }
150 
151  /* We can now attempt to receive that message
152  * Notice we are binding as the recipient of the message
153  */
154 
155  status = X400msOpen (contype, recip, def_dn, password, ms_pa, &nummsg, &sp);
156  if ( status != X400_E_NOERROR ) {
157  fprintf (stderr, "Error in Open: %s\n", X400msError (status));
158  exit (status);
159  }
160 
161  /* sp is obviously a session pointer
162  * nummsgs is an int represtenting the number of messages available
163  * for the current user
164  */
165  receive_msgs(sp,nummsg);
166 
167  X400msClose (sp);
168  if ( status != X400_E_NOERROR ) {
169  fprintf (stderr, "Error in Close: %s\n", X400msError (status));
170  exit (status);
171  }
172 
173  return 0;
174 }
175 
176 
177 /*
178  * 1) Sending a "Hello World!" email
179  *
180  * You will need to know a single X.400 email addresses.
181  * This email address needs to be routed to use the Gateway channel.
182  *
183  * Fortunately quickconfig helps by providing a suitable user:
184  * /CN=GatewayUser/OU=Sales/OU=HOSTNAME/O=GatewayMTA/PRMD=TestPRMD/ADMD=TestADMD/C=GB/
185  *
186  * You should alter "HOSTNAME" to being the correct value for your
187  * configuration.
188  *
189  * The following section will show you how to send a "Hello World!"
190  * X.400 email througth the messag transfer API.
191  */
192 
193 static void send_hello_world(
194  struct X400msSession *sp
195 )
196 {
197  int status;
198 
199  /* Now lets create a new message */
200  struct X400msMessage *mp; /* This is the pointer to a message object */
201  struct X400Recipient *rp; /* This is the pointer to a new recipient */
202 
203 
204  printf("Now sending the simple message\n");
205  /* We now need to create a new message object, and have the new
206  * message object associated with the session object.
207  *
208  * To do this we use X400mtMsgNew.
209  */
210  status = X400msMsgNew (sp, X400_MSG_MESSAGE, &mp);
211 
212  if ( status != X400_E_NOERROR ) {
213  fprintf (stderr, "Error in MsgNew: %s\n", X400msError (status));
214  exit (status);
215  }
216 
217  /* We can now manipulate the message object */
218 
219  /* Add an originator. Similar concepts here,
220  * we are manipulating the message object to add an originator address
221  */
222  status = X400msMsgAddStrParam (mp, X400_S_OR_ADDRESS, orig, -1);
223 
224  if ( status != X400_E_NOERROR ) {
225  fprintf (stderr, "Error adding orignator: %s\n", X400msError (status));
226  exit (status);
227  }
228 
229  /* Create a new recipient object, and associate it with the message object.
230  */
231  status = X400msRecipNew (mp, X400_RECIP_STANDARD, &rp);
232  if ( status != X400_E_NOERROR ) {
233  fprintf (stderr, "Error adding recipient: %s\n", X400msError (status));
234  exit (status);
235  }
236 
237  /* We can now manipulate the recipient object and add the following:
238  * 1) The OR address of the recipient.
239  * Obviously this is important, otherwise the message cannot be routed.
240  *
241  * 2) The responsibility value
242  * You don't actually need to set this. However it is usefull to see
243  * how the attributes being manipulated correspond with the standards.
244  */
245  status = X400msRecipAddStrParam (rp, X400_S_OR_ADDRESS, recip, -1);
246  if ( status != X400_E_NOERROR ) {
247  fprintf (stderr, "Error adding recipient address: %s\n",
248  X400msError (status));
249  exit (status);
250  }
251 
252  /* The following attribute might be slightly confusing.
253  * The best thing to do at this point is to take a brief look
254  * at X.411, section 12.2.1.1.1.6, this describes the responsibility
255  * attribute.
256  */
257 
259  if ( status != X400_E_NOERROR ) {
260  fprintf (stderr, "Error adding recipient responsibility: %s\n",
261  X400msError (status));
262  exit (status);
263  }
264 
265  /* And now for the content */
266  {
267  char *content = "Hello World!";
268  char *subject = "A simple test message";
269 
270  status = X400msMsgAddStrParam (mp,X400_T_IA5TEXT, content , -1);
271  if ( status != X400_E_NOERROR ) {
272  fprintf (stderr, "Error adding content : %s\n",
273  X400msError (status));
274  exit (status);
275  }
276 
277  status = X400msMsgAddStrParam (mp, X400_S_SUBJECT, subject, -1);
278  if ( status != X400_E_NOERROR ) {
279  fprintf (stderr, "Error adding subject : %s\n",
280  X400msError (status));
281  exit (status);
282  }
283  }
284 
285  /* we should now be able to send the message */
286  status = X400msMsgSend (mp);
287  if ( status != X400_E_NOERROR ) {
288  fprintf (stderr, "Error in MsgSend: %s\n", X400msError (status));
289  exit (status);
290  }
291 
292  /* We can now delete the message
293  * We pass in the message pointer, but also a "0".
294  * The "0" means that the message will not be */
295  status = X400msMsgDelete (mp,0);
296  if ( status != X400_E_NOERROR ) {
297  fprintf (stderr, "Error in X400mtMsgDelete: %s\n", X400msError (status));
298  exit (status);
299  }
300 
301  printf("Sent message\n");
302 }
303 
304 
305 static void receive_msgs(
306  struct X400msSession *sp,
307  int nummsg
308 )
309 {
310 
311  struct X400msMessage *mp;
312  struct X400Recipient *rp;
313 
314  int status;
315 
316  int type;
317  int seqn;
318  size_t length;
319  char buffer[BUFSIZ];
320 
321  if (nummsg == 0) {
322  printf ("no messages - waiting 60 seconds for a message to be delivered.....\n");
323  }
324  else {
325  printf("%d messages waiting\n", nummsg);
326  }
327 
328  /* This will add a delay, so the sent message will have sometime to get
329  * through the system
330  */
331  status = X400msWait(sp, 1, &nummsg);
332  if (status != X400_E_NOERROR) {
333  fprintf(stderr, "Error from Wait: %s\n", X400msError(status));
334  return;
335  }
336 
337  /* Now we fetch the actual message.
338  * to keep things simple we will only try to fetch the first message
339  */
340  status = X400msMsgGet(sp, 0, &mp, &type, &seqn);
341  switch (status) {
342  case X400_E_NOERROR:
343  fprintf(stderr, "MsgGet successfully got message\n");
344  break;
345  default :
346  fprintf(stderr, "Error from MsgGet: %s\n", X400msError(status));
347  return;
348  }
349 
350  /* Now we fetch various attrbitues.
351  * A word of warning though:
352  * These attributes may or may not be present in real messages.
353  * we know exactly what attributes are avaliable in this test message.
354  * so we will keep it simple and only bother checking these few */
355 
356  /* Fetch the originator */
358  buffer, sizeof buffer, &length);
359  if (status != X400_E_NOERROR) {
360  fprintf(stderr, "Error from MsgGetStrParam: %s\n",
361  X400msError(status));
362  return;
363  }
364  printf("Originator: %.*s\n", (int)length, buffer);
365 
366  /* Fetch the Envelope recipient */
367  status = X400msRecipGet(mp, X400_RECIP_ENVELOPE, 1, &rp);
368  if (status == X400_E_NO_RECIP)
369  return;
370 
371  if (status != X400_E_NOERROR) {
372  fprintf(stderr, "Error from RecipGet: %s\n", X400msError(status));
373  /* tidily close the session */
374  status = X400msClose(sp);
375  exit(status);
376  }
377 
378  /* Now fetch the OR Address of the recipient.
379  * We can safely assume that there is an OR Address since we created the
380  * message.*/
382  buffer, sizeof buffer, &length);
383  if (status != X400_E_NOERROR) {
384  fprintf(stderr, "Error from X400msRecipGetStrParam: %s\n",
385  X400msError(status));
386  return;
387  }
388  printf("Envelope Recipient : %.*s\n", (int)length, buffer);
389 
390 
391  /* Now fetch the Content type int */
392  status = X400msMsgGetIntParam (mp, X400_N_CONTENT_TYPE, &type);
393  if ( status != X400_E_NOERROR ) {
394  fprintf (stderr, "Error in X400msMsgGetIntParam content type: %s\n",
395  X400msError (status));
396  return;
397  }
398  printf("Content type: %i\n",type);
399 
400 
401  /* Now fetch the subject of the message */
403  buffer, sizeof buffer, &length);
404  if ( status != X400_E_NOERROR ) {
405  fprintf (stderr, "Error in X400msMsgGetStrParam subject: %s\n",
406  X400msError (status));
407  return;
408  }
409 
410  printf("Subject: %.*s\n", (int)length, buffer);
411 
412  /* Now fetch the IA5-text content of the message.*/
413  /* NB this (unwisely) assumes that the first attachment
414  * is an IA5 attachment */
416  buffer, sizeof buffer, &length);
417  if ( status != X400_E_NOERROR ) {
418  fprintf (stderr, "Error in X400msMsgGetStrParam subject: %s\n",
419  X400msError (status));
420  } else {
421  printf("Text:\n%.*s\n", (int)length, buffer);
422  }
423 
424  /* get all the attachments */
425  get_body_parts(mp);
426 
427  X400msMsgDelete(mp, 0);
428 }
#define X400_MSG_MESSAGE
Definition: x400_att.h:29
#define X400_S_LOG_CONFIGURATION_FILE
Definition: x400_att.h:1091
int X400msSetStrDefault(struct X400msSession *sp, int paramtype, const char *value, size_t length)
Set a default string parameter value in a session.
int X400msMsgGetIntParam(struct X400msMessage *mp, int paramtype, int *valp)
Return a integer-valued parameter from the message object.
int X400msMsgAddStrParam(struct X400msMessage *mp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
#define X400_N_RESPONSIBILITY
Definition: x400_att.h:642
int X400msRecipAddIntParam(struct X400Recipient *rp, int paramtype, int value)
Add integer-valued parameter to the message.
int X400msMsgGet(struct X400msSession *sp, int number, struct X400msMessage **mpp, int *typep, int *seqp)
Get message object for transfer out from MS or MTA via P3.
const char * X400msError(int error)
Obtain a string describing the meaning of the given error code.
#define X400_E_NO_RECIP
Definition: x400_att.h:109
int X400msMsgNew(struct X400msSession *sp, int type, struct X400msMessage **mpp)
Creates new message.
int X400msClose(struct X400msSession *sp)
Close a X400 Session.
int X400msRecipGet(struct X400msMessage *mp, int type, int number, struct X400Recipient **rpp)
Get recipient object from message.
int X400msRecipAddStrParam(struct X400Recipient *rp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
#define X400_T_IA5TEXT
Definition: x400_att.h:798
#define X400_E_NOERROR
Definition: x400_att.h:46
int X400msOpen(int type, const char *oraddr, const char *dirname, const char *credentials, const char *pa, int *messages, struct X400msSession **spp)
Open a session to a Message Store (P7) or MTA (P3) in synchronous mode.
#define X400_S_OR_ADDRESS
Definition: x400_att.h:349
#define X400_N_CONTENT_TYPE
Definition: x400_att.h:408
int X400msMsgGetStrParam(struct X400msMessage *mp, int paramtype, char *buffer, size_t buflen, size_t *paramlenp)
Return a string-valued parameter from the message object.
#define X400_RECIP_STANDARD
Definition: x400_att.h:341
int X400msMsgSend(struct X400msMessage *mp)
Send message object.
int X400msRecipGetStrParam(struct X400Recipient *rp, int paramtype, char *buffer, size_t buflen, size_t *paramlenp)
Return a string-valued parameter from the recipient object.
X400 MA/MS (P3/P7) Interface.
int X400msRecipNew(struct X400msMessage *mp, int type, struct X400Recipient **rpp)
Add new recipient to a message.
int X400msWait(struct X400msSession *sp, int seconds, int *count)
Wait for messages to be ready to be read.
#define X400_S_SUBJECT
Definition: x400_att.h:722
#define X400_RECIP_ENVELOPE
Definition: x400_att.h:335
int X400msMsgDelete(struct X400msMessage *mp, int retain)
Delete message object.