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
81char *orig = "/CN=P7User1/OU=Sales/O="HOSTNAME"/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
82char *recip = "/CN=P7User2/OU=Sales/O="HOSTNAME"/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
83char *ms_pa = "\"3001\"/Internet="FQ_HOSTNAME"+3001"; /*Message Store presentation address */
84
85char *password = "secret"; /* password used to bind to the store */
86
87static void send_hello_world(
88 struct X400msSession *sp
89);
90
91static void receive_msgs(
92 struct X400msSession *sp,
93 int nummsg
94);
95
96int 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
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
193static 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
305static 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}
int X400msMsgAddStrParam(struct X400msMessage *mp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
int X400msRecipGet(struct X400msMessage *mp, int type, int number, struct X400Recipient **rpp)
Get recipient object from message.
int X400msRecipAddIntParam(struct X400Recipient *rp, int paramtype, int value)
Add integer-valued parameter to the message.
int X400msMsgGetStrParam(struct X400msMessage *mp, int paramtype, char *buffer, size_t buflen, size_t *paramlenp)
Return a string-valued parameter from the 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.
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.
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.
int X400msRecipAddStrParam(struct X400Recipient *rp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
int X400msMsgSend(struct X400msMessage *mp)
Send message object.
int X400msMsgDelete(struct X400msMessage *mp, int retain)
Delete message object.
int X400msMsgNew(struct X400msSession *sp, int type, struct X400msMessage **mpp)
Creates new message.
int X400msClose(struct X400msSession *sp)
Close a X400 Session.
int X400msSetStrDefault(struct X400msSession *sp, int paramtype, const char *value, size_t length)
Set a default string parameter value in a session.
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.
int X400msMsgGetIntParam(struct X400msMessage *mp, int paramtype, int *valp)
Return a integer-valued parameter from the message object.
#define X400_S_OR_ADDRESS
Definition x400_att.h:349
#define X400_S_SUBJECT
Definition x400_att.h:749
#define X400_T_IA5TEXT
Definition x400_att.h:825
#define X400_S_LOG_CONFIGURATION_FILE
Definition x400_att.h:1116
#define X400_N_CONTENT_TYPE
Definition x400_att.h:419
#define X400_E_NOERROR
Definition x400_att.h:46
#define X400_E_NO_RECIP
Definition x400_att.h:109
#define X400_MSG_MESSAGE
Definition x400_att.h:29
#define X400_N_RESPONSIBILITY
Definition x400_att.h:669
#define X400_RECIP_STANDARD
Definition x400_att.h:341
#define X400_RECIP_ENVELOPE
Definition x400_att.h:335
X400 MA/MS (P3/P7) Interface.

All rights reserved © 2002 - 2024 Isode Ltd.