x400_mttutorial.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_mttutorial.c
12 *
13 * The purpose of this file is to simply explain how to send and receive
14 * X400 email messages using the Message Transfer (Gateway) API.
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#include <stdio.h>
41#include <stdlib.h>
42
43
44#include <x400_mtapi.h>
45#include "example.h"
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49#include <errno.h>
50#include <time.h>
51
52/* Define IC_ATTRIBUTE
53 * For gcc/g++ this becomes __attribute__ and is used for the printf type
54 * format checking.
55 * Defined to be empty for other compilers
56 */
57
58#if defined(__GNUC__) || defined (__GNUG__)
59#define IC_ATTRIBUTE(x) __attribute__ (x)
60#else
61#define IC_ATTRIBUTE(x)
62#endif
63
64/* To annotate function parameters which are known not to be used
65 * Not in gcc/g++ prior to v4 (I think)
66 */
67#if (defined(__GNUG__) && __GNUG__ >= 4) || (!defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 3)
68# define ARGNOTUSED IC_ATTRIBUTE((unused))
69#else
70# define ARGNOTUSED
71#endif
72
73char *orig = "/CN=GatewayUser/OU=Sales/OU=dhcp-164/O=GatewayMTA/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
74char *recip = "/CN=GatewayUser/OU=Sales/OU=dhcp-164/O=GatewayMTA/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
75
76static void send_hello_world(
77 struct X400mtSession *sp
78);
79
80static void receive_hello_world(
81 struct X400mtSession *sp
82);
83
84int main (int argc ARGNOTUSED, char ** argv ARGNOTUSED)
85{
86 int status;
87 struct X400mtSession *sp; /* This is the session pointer object.
88 * All susequent objects like message objects
89 * are associated back to this session
90 * When the session is closed these objects are
91 * free'd.
92 */
93
94 /* Open a new session, and check that the session has been opened ok.
95 * The different values the API can return are in x400_att.h */
96
97 status = X400mtOpen (x400_channel, &sp);
98 if ( status != X400_E_NOERROR ) {
99 fprintf (stderr, "Error in Open: %s\n", X400mtError (status));
100 exit (status);
101 }
102
103 /* We now want to configure logging
104 * Isode logging is configured using a specific XML file.
105 * a GUI editor SBINDIR/logconfig allows you to easily alter the XML file.
106 *
107 * To specify a particular xml file, we need to manipulate the
108 * session object.
109 *
110 * To do this we call X400mtSetStrDefault, passing in the session
111 * pointer, the attribute of the object we wish to manipulate
112 * (X400_S_LOG_CONFIGURATION_FILE), the filename, and the size in bytes
113 * of the filename.
114 *
115 * Since we don't actually have the size of the filename in bytes,
116 * we can pass in 0 or -1 in for the size field. The underlying code will
117 * calculate the size for us.
118 */
119
121
122 /* The reference section of the API manual contains descriptions of
123 * other default attributes you may set.
124 */
125
126 /* We can now attempt to send a message */
127 send_hello_world(sp);
128
129
130
131 /* We can now attempt to receive a message */
132 receive_hello_world(sp);
133
134 X400mtClose (sp);
135 if ( status != X400_E_NOERROR ) {
136 fprintf (stderr, "Error in Close: %s\n", X400mtError (status));
137 exit (status);
138 }
139
140 return 0;
141}
142
143
144/*
145 * 1) Sending a "Hello World!" email
146 *
147 * You will need to know a single X.400 email addresses.
148 * This email address needs to be routed to use the Gateway channel.
149 *
150 * Fortunately quickconfig helps by providing a suitable user:
151 * /CN=GatewayUser/OU=Sales/OU=HOSTNAME/O=GatewayMTA/PRMD=TestPRMD/ADMD=TestADMD/C=GB/
152 *
153 * You should alter "HOSTNAME" to being the correct value for your
154 * configuration.
155 *
156 * The following section will show you how to send a "Hello World!"
157 * X.400 email througth the messag transfer API.
158 */
159
160static void send_hello_world(
161 struct X400mtSession *sp
162)
163{
164 int status;
165
166 /* Now lets create a new message */
167 struct X400mtMessage *mp; /* This is the pointer to a message object */
168 struct X400Recipient *rp; /* This is the pointer to a new recipient */
169
170
171 printf("Now sending simple message\n");
172 /* We now need to create a new message object, and have the new
173 * message object associated with the session object.
174 *
175 * To do this we use X400mtMsgNew.
176 */
177 status = X400mtMsgNew (sp, X400_MSG_MESSAGE, &mp);
178
179 if ( status != X400_E_NOERROR ) {
180 fprintf (stderr, "Error in MsgNew: %s\n", X400mtError (status));
181 exit (status);
182 }
183
184 /* We can now manipulate the message object */
185
186 /* Add an originator. Similar concepts here,
187 * we are manipulating the message object to add an originator address
188 */
189 status = X400mtMsgAddStrParam (mp, X400_S_OR_ADDRESS, orig, -1);
190
191 if ( status != X400_E_NOERROR ) {
192 fprintf (stderr, "Error adding orignator: %s\n", X400mtError (status));
193 exit (status);
194 }
195
196 /* Create a new recipient object, and associate it with the message object.
197 */
198 status = X400mtRecipNew (mp, X400_RECIP_STANDARD, &rp);
199 if ( status != X400_E_NOERROR ) {
200 fprintf (stderr, "Error adding recipient: %s\n", X400mtError (status));
201 exit (status);
202 }
203
204 /* We can now manipulate the recipient object and add the following:
205 * 1) The OR address of the recipient.
206 * Obviously this is important, otherwise the message cannot be routed.
207 *
208 * 2) The responsibility value
209 * You don't actually need to set this. However it is usefull to see
210 * how the attributes being manipulated correspond with the standards.
211 */
212 status = X400mtRecipAddStrParam (rp, X400_S_OR_ADDRESS, recip, -1);
213 if ( status != X400_E_NOERROR ) {
214 fprintf (stderr, "Error adding recipient address: %s\n",
215 X400mtError (status));
216 exit (status);
217 }
218
219 /* The following attribute might see slightly confusing.
220 * The best thing to do at this point is to take a brief look
221 * at X.411, section 12.2.1.1.1.6, this describes the responsibility
222 * attribute.
223 */
224
226 if ( status != X400_E_NOERROR ) {
227 fprintf (stderr, "Error adding recipient responsibility: %s\n",
228 X400mtError (status));
229 exit (status);
230 }
231
232 /* Extra envelope attributes */
234 if ( status != X400_E_NOERROR ) {
235 fprintf (stderr, "Error adding Content type : %s\n",
236 X400mtError (status));
237 exit (status);
238 }
239
240 /* And now for the content */
241 {
242 char *content = "Hello World!";
243 char *subj = "A simple test message";
244
245 status = X400mtMsgAddStrParam (mp,X400_T_IA5TEXT, content , -1);
246 if ( status != X400_E_NOERROR ) {
247 fprintf (stderr, "Error adding content : %s\n",
248 X400mtError (status));
249 exit (status);
250 }
251
252 status = X400mtMsgAddStrParam (mp, X400_S_SUBJECT, subj, -1);
253 if ( status != X400_E_NOERROR ) {
254 fprintf (stderr, "Error adding subject : %s\n",
255 X400mtError (status));
256 exit (status);
257 }
258 }
259
260 /* we should now be able to send the message */
261 status = X400mtMsgSend (mp);
262 if ( status != X400_E_NOERROR ) {
263 fprintf (stderr, "Error in MsgSend: %s\n", X400mtError (status));
264 exit (status);
265 }
266
267 /* We can now delete the message */
268 status = X400mtMsgDelete (mp);
269 if ( status != X400_E_NOERROR ) {
270 fprintf (stderr, "Error in X400mtMsgDelete: %s\n", X400mtError (status));
271 exit (status);
272 }
273
274 printf("Sent message\n");
275}
276
277
278static void receive_hello_world(
279 struct X400mtSession *sp
280)
281{
282 struct X400mtMessage *mp;
283 int status;
284 int type;
285 char buffer[BUFSIZ];
286 size_t length;
287
288 printf("Now fetching message\n");
289
290 status = X400mtMsgGetStart (sp, &mp, &type);
291 if ( status != X400_E_NOERROR ) {
292 fprintf (stderr, "Error in X400mtMsgGetStart: %s\n",
293 X400mtError (status));
294 exit (status);
295 }
296
297 switch ( type) {
298 case X400_MSG_REPORT:
299 printf("Got a report\n");
300 exit(0);
301 case X400_MSG_PROBE:
302 printf("Got a probe\n");
303 exit(0);
304 case X400_MSG_MESSAGE:
305 break;
306 }
307
308 /* Get the originator */
310 buffer, sizeof buffer , &length);
311 if(status == X400_E_NOERROR) {
312 printf ("Originator: %.*s\n",(int)length,buffer);
313 } else if (status == X400_E_NOSPACE) {
314 /* This is an interesting error.
315 * It means that the size of buffer is too small for the originator
316 * address. The correct thing to do here is to create a buffer
317 * of size length bytes to hold the value.
318 *
319 * All of the GetStrParam functions work in this way.
320 */
321
322 char * big_buff = NULL;
323 big_buff = (char *) malloc((sizeof(char)) * length);
325 big_buff, length , &length);
326 if (status != X400_E_NOERROR) {
327 fprintf(stderr, "Error in getting originator address: %s\n",
328 X400mtError (status));
329 exit (status);
330 }
331 printf("Large Originator: %.*s\n",(int)length,big_buff);
332 free(big_buff);
333
334 } else {
335 fprintf (stderr, "Error in getting originator address: %s\n",
336 X400mtError (status));
337 exit (status);
338 }
339
340 {
341 /* Fetching recipients
342 *
343 * Within the message there are 1 or more recipients.
344 * so it is important to try to read through the whole list.
345 *
346 * All list objects work in this same way.
347 */
348 int n;
349 struct X400Recipient *rp; /* Pointer to recipient object */
350 for ( n = 1; ; n++ ) {
351 /* Get the next recipient object with a "Get" command
352 * Notice that I'm using the "X400_RECIP_ENVELOPE".
353 * IE this is fetching recipients from the envelope.
354 * We can fetch recipients from the message header as well
355 * Using X400_RECIP_PRIMARY / X400_RECIP_CC / ETC
356 */
357 status = X400mtRecipGet (mp, X400_RECIP_ENVELOPE, n, &rp);
358 if ( status == X400_E_NO_RECIP ) {
359 printf("Got final recipient\n");
360 break;
361 } else if ( status != X400_E_NOERROR ) {
362 fprintf (stderr, "Error fetching recipients: %s\n",
363 X400mtError (status));
364 exit(status);
365 }
366
367 /* Now we have a recipient object that represents a single
368 recipient.
369 */
370
372 buffer, BUFSIZ, &length);
373 if ( status == X400_E_NOERROR ) {
374 printf ("%s recipient %d: %.*s\n", buffer, n,
375 (int)length, buffer);
376 } else {
377 fprintf (stderr, "Error fetching OR Address: %s\n",
378 X400mtError (status));
379 exit (status);
380 }
381
382 /* It is possible to continue to try to obtain other recipient
383 information. However lets keep it simple here
384 */
385
386 }
387 }/* end of fetch recips*/
388
389 /* Now lets obtain the subject of the message */
390 /* Subject */
392 buffer, sizeof buffer , &length);
393 if ( status == X400_E_NOERROR ) {
394 printf ("Subject: %.*s\n", (int)length, buffer);
395 } else {
396 fprintf (stderr, "Error fetching subject: %s\n",
397 X400mtError (status));
398 exit (status);
399 }
400
401 /* Followed by the message content (Hello World).
402 * The message we just created contained an ia5-text bodypart
403 * so lets request that
404 * NB this (unwisely) assumes that the first attachment
405 * is an IA5 attachment
406 */
408 buffer, sizeof buffer , &length);
409 if ( status == X400_E_NOERROR ) {
410 printf ("Text:\n%.*s\n", (int)length, buffer);
411 } else {
412 fprintf (stderr, "Error fetching ia5-text bodypart: %s\n",
413 X400mtError (status));
414 }
415
416 /* Now that we've got the message we need to let the MTA know the message
417 * has been transfered ok*/
418 status = X400mtMsgGetFinish (mp, X400_E_NOERROR, -1, -1, "");
419 if ( status != X400_E_NOERROR ) {
420 printf("X400mtMsgFinish returned error %d\n", status);
421 fprintf (stderr, "Error in X400mtMsgFinish: %s\n",
422 X400mtError (status));
423 }
424
425 /* And now we can delete our own copy of the message */
426 status = X400mtMsgDelete (mp);
427 if ( status != X400_E_NOERROR ) {
428 printf("X400mtMsgDelete returned error %d\n", status);
429 fprintf (stderr, "Error in X400mtMsgDelete: %s\n",
430 X400mtError (status));
431 }
432
433}
434
int X400mtMsgGetStrParam(struct X400mtMessage *mp, int paramtype, char *buffer, size_t buflen, size_t *paramlenp)
Return a string-valued parameter from the message object.
int X400mtMsgAddStrParam(struct X400mtMessage *mp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
int X400mtRecipNew(struct X400mtMessage *mp, int type, struct X400Recipient **rpp)
Add new recipient to a message.
int X400mtRecipAddStrParam(struct X400Recipient *rp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
int X400mtSetStrDefault(struct X400mtSession *sp, int paramtype, const char *value, size_t length)
Set a default string parameter value in a session.
int X400mtMsgDelete(struct X400mtMessage *mp)
Delete message object.
const char * X400mtError(int error)
Return string for error code.
int X400mtMsgSend(struct X400mtMessage *mp)
Send message object to MTA.
int X400mtMsgNew(struct X400mtSession *sp, int type, struct X400mtMessage **mpp)
Creates new message.
int X400mtRecipGetStrParam(struct X400Recipient *rp, int paramtype, char *buffer, size_t buflen, size_t *paramlenp)
Return a string-valued parameter from the recipient object.
int X400mtRecipGet(struct X400mtMessage *mp, int type, int number, struct X400Recipient **rpp)
Get recipient object from message.
int X400mtMsgGetFinish(struct X400mtMessage *mp, int status, int reason, int diag, const char *info)
Finish transfer-out of message from MTA, generate DR if required.
int X400mtClose(struct X400mtSession *sp)
Close a X400 Session.
int X400mtMsgAddIntParam(struct X400mtMessage *mp, int paramtype, int value)
Add integer-valued parameter to the message.
int X400mtMsgGetStart(struct X400mtSession *sp, struct X400mtMessage **mpp, int *typep)
Get message object for transfer out from MTA.
int X400mtRecipAddIntParam(struct X400Recipient *rp, int paramtype, int value)
Add integer-valued parameter to the message.
#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_NOSPACE
Definition x400_att.h:112
#define X400_E_NO_RECIP
Definition x400_att.h:109
#define X400_MSG_REPORT
Definition x400_att.h:32
#define X400_MSG_PROBE
Definition x400_att.h:35
#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
X.400 Gateway Interface.
#define X400mtOpen(p1, p2)
Definition x400_mtapi.h:999

All rights reserved © 2002 - 2024 Isode Ltd.