/* AS/400 SMTP Mail Sender Utility This small program that is furnished by IBM is a simple example to provide an illustration. This example has not been thoroughly tested under all conditions. IBM, therefore, cannot guarantee or imply reliability, serviceability, or function of this program. All programs contained herein are provided to you "AS IS". THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. */ /**********************************************************************/ /* */ /* Name: mail.c */ /* */ /* Description: This program is bare SMTP client- reads from stdin */ /* It connects to 'mail' or a specified SMTP server. */ /* This source is self-contained and only includes */ /* system header files. */ /* */ /* To compile this program, issue the following CL */ /* command. (Assuming the correct source location) */ /* CRTBNDC PGM(UTILS/MAIL) SRCSTMF('/src/mail.c') */ /* */ /* Create a link in the IFS to use this program with */ /* Qshell using the following command: */ /* ln -s /qsys.lib/utils.lib/mail.pgm /usr/bin/mail */ /* */ /* Usage: mail user[@hostname] [SMTP server] */ /* Note: default SMTP server is 'mail' \n"); */ /* */ /* This is particularly useful with Qshell: */ /* mail somebody@somewhere.com < test.txt */ /* */ /* If compiled with DEFINE(DEBUG) you will see */ /* the SMTP responses from the server. */ /* */ /**********************************************************************/ /**********************************************************************/ /* Includes */ /**********************************************************************/ #include /* perror() */ #include /* socket(), bind(), etc. */ #include /* sockaddr_in, INADDR_ANY, etc. */ #include /* close(), read(), write() etc. */ #include /* exit() */ #include /* exit(), memset() */ #include /* errno and values */ #include /* inet_addr() */ #include /* gethostbyname() */ #include /* sigaction(), etc. */ #include /* getuid(), getpwuid() */ #include /* tolower() */ /**********************************************************************/ /* Constants */ /**********************************************************************/ #define SMTP_PORT 25 #define DEFAULT_BUF 4096 /**********************************************************************/ /* Types */ /**********************************************************************/ /* typedef unsigned char uchar; */ /**********************************************************************/ /* Global Variables */ /**********************************************************************/ char *sysname; /* Long host name of server system */ char *buffer; /* Buffer for i/o */ /* EBCDIC to ASCII translation table */ static unsigned char AsciiTable[256] = { 0x00,0x01,0x02,0x03,0x20,0x09,0x20,0x7f, /* 00-07 */ 0x20,0x20,0x20,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ 0x10,0x11,0x12,0x13,0x20,0x0a,0x08,0x20, /* 10-17 */ 0x18,0x19,0x20,0x20,0x20,0x1d,0x1e,0x1f, /* 18-1f */ 0x20,0x20,0x1c,0x20,0x20,0x0a,0x17,0x1b, /* 20-27 */ 0x20,0x20,0x20,0x20,0x20,0x05,0x06,0x07, /* 28-2f */ 0x20,0x20,0x16,0x20,0x20,0x20,0x20,0x04, /* 30-37 */ 0x20,0x20,0x20,0x20,0x14,0x15,0x20,0x1a, /* 38-3f */ 0x20,0x20,0x83,0x84,0x85,0xa0,0xc6,0x86, /* 40-47 */ 0x87,0xa4,0xbd,0x2e,0x3c,0x28,0x2b,0x7c, /* 48-4f */ 0x26,0x82,0x88,0x89,0x8a,0xa1,0x8c,0x8b, /* 50-57 */ 0x8d,0xe1,0x21,0x24,0x2a,0x29,0x3b,0xaa, /* 58-5f */ 0x2d,0x2f,0xb6,0x8e,0xb7,0xb5,0xc7,0x8f, /* 60-67 */ 0x80,0xa5,0xdd,0x2c,0x25,0x5f,0x3e,0x3f, /* 68-6f */ 0x9b,0x90,0xd2,0xd3,0xd4,0xd6,0xd7,0xd8, /* 70-77 */ 0xde,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22, /* 78-7f */ 0x9d,0x61,0x62,0x63,0x64,0x65,0x66,0x67, /* 80-87 */ 0x68,0x69,0xae,0xaf,0xd0,0xec,0xe7,0xf1, /* 88-8f */ 0xf8,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, /* 90-97 */ 0x71,0x72,0xa6,0xa7,0x91,0xf7,0x92,0xcf, /* 98-9f */ 0xe6,0x7e,0x73,0x74,0x75,0x76,0x77,0x78, /* a8-a7 */ 0x79,0x7a,0xad,0xa8,0xd1,0xed,0xe8,0xa9, /* a8-af */ 0x5e,0x9c,0xbe,0xfa,0xb8,0x15,0x14,0xac, /* b0-b7 */ 0xab,0xf3,0x5b,0x5d,0xee,0xf9,0xef,0x9e, /* b8-bf */ 0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47, /* c0-c7 */ 0x48,0x49,0xf0,0x93,0x94,0x95,0xa2,0xe4, /* c8-cf */ 0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50, /* d0-d7 */ 0x51,0x52,0xfb,0x96,0x81,0x97,0xa3,0x98, /* d8-df */ 0x5c,0xf6,0x53,0x54,0x55,0x56,0x57,0x58, /* e0-e7 */ 0x59,0x5a,0xfc,0xe2,0x99,0xe3,0xe0,0xe5, /* e8-ef */ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, /* f0-f7 */ 0x38,0x39,0xfd,0xea,0x9a,0xeb,0xe9,0xff /* f8-ff */ }; /* ASCII to EBCDIC translation table */ static unsigned char EbcdicTable[256] = { 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, /* 00-07 */ 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, /* 10-17 */ 0x18,0x19,0x3f,0x27,0x22,0x1d,0x1e,0x1f, /* 18-1f */ 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, /* 20-27 */ 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, /* 28-2f */ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, /* 30-37 */ 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, /* 38-3f */ 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, /* 40-47 */ 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, /* 48-4f */ 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, /* 50-57 */ 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, /* 58-5f */ 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, /* 60-67 */ 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, /* 68-6f */ 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, /* 70-77 */ 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, /* 78-7f */ 0x68,0xdc,0x51,0x42,0x43,0x44,0x47,0x48, /* 80-87 */ 0x52,0x53,0x54,0x57,0x56,0x58,0x63,0x67, /* 88-8f */ 0x71,0x9c,0x9e,0xcb,0xcc,0xcd,0xdb,0xdd, /* 90-97 */ 0xdf,0xec,0xfc,0x70,0xb1,0x80,0xbf,0x40, /* 98-9f */ 0x45,0x55,0xee,0xde,0x49,0x69,0x9a,0x9b, /* a8-a7 */ 0xab,0xaf,0x5f,0xb8,0xb7,0xaa,0x8a,0x8b, /* a8-af */ 0x40,0x40,0x40,0x40,0x40,0x65,0x62,0x64, /* b0-b7 */ 0xb4,0x40,0x40,0x40,0x40,0x4a,0xb2,0x40, /* b8-bf */ 0x40,0x40,0x40,0x40,0x40,0x40,0x46,0x66, /* c0-c7 */ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x9f, /* c8-cf */ 0x8c,0xac,0x72,0x73,0x74,0x89,0x75,0x76, /* d0-d7 */ 0x77,0x40,0x40,0x40,0x40,0x6a,0x78,0x40, /* d8-df */ 0xee,0x59,0xeb,0xed,0xcf,0xef,0xa0,0x8e, /* e0-e7 */ 0xae,0xfe,0xfb,0xfd,0x8d,0xad,0xbc,0xbe, /* e8-ef */ 0xca,0x8f,0x40,0xb9,0xb6,0xb5,0xe1,0x9d, /* f0-f7 */ 0x90,0xbd,0xb3,0xda,0xea,0xfa,0x40,0x40 /* f8-ff */ }; /**********************************************************************/ /* Function Prototypes */ /**********************************************************************/ void MySignalHandler(int); void usage(void); char* EtoA(unsigned char*); char* AtoE(unsigned char*); void response(int); int main (int argc, char *argv[]) { struct sigaction sigact; /* Signal action */ char c; int port=SMTP_PORT; /* Port to connect to on server */ int sd; /* Socket to server */ int rc; /* Return code */ struct sockaddr_in svr_addr; /* AF_INET socket address */ long ip_addr; /* IP address of server system */ struct in_addr host_addr; /* Host address for gethostbyaddr() */ char* hostname; /* Short host name of server system */ char* username; /* recipient user name */ size_t len; /* Length of input string */ struct hostent *host_p; /* Pointer to hostent structure returned by gethostbyname() */ int buf_size; /* Amount of data read from server */ struct passwd *pd; /* user info */ char* tempptr; /* temp pointer */ /********************************************************************/ /* Initialization. */ /********************************************************************/ /* Set up a signal handler for SIGINT. The signal is sent to the process when the user presses c. */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigact.sa_handler = MySignalHandler; if (sigaction(SIGINT, &sigact, NULL) != 0) { perror("mail: sigaction(SIGINT) failed"); exit(1); } /* Allocate buffers for translating input */ buffer = (char *)malloc(DEFAULT_BUF); memset(buffer, '\0', DEFAULT_BUF); /********************************************************************/ /* Process the input parameters. */ /********************************************************************/ /* set up user and host from command line user@host */ switch(argc){ case 2: hostname = "mail"; break; case 3: hostname = argv[2]; break; default: usage(); break; } username = argv[1]; /* Convert a dotted decimal address to a 32-bit IP address. */ ip_addr = inet_addr(hostname); /* When inet_addr() returns -1 we'll assume the user specified a host name. */ if (ip_addr == -1) { /* Try to find the host by name. */ host_p = gethostbyname(hostname); if (host_p) { memcpy(&ip_addr, host_p->h_addr, host_p->h_length); sysname = host_p->h_name; } else { fprintf(stderr, "mail: Could not find host %s\n", hostname); exit(1); } } /* End of if */ /* The user specified a IP address. */ else { /* Try to find the host by address. */ host_addr.s_addr = ip_addr; host_p = gethostbyaddr((char *)&host_addr.s_addr, sizeof(host_addr), AF_INET); if (host_p) { sysname = host_p->h_name; } else { fprintf(stderr, "mail: Could not find host %s\n", hostname); exit(1); } } /* End of else */ /********************************************************************/ /* Connect to the smtp server on the specified system. */ /********************************************************************/ /* Create a socket. */ if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) { perror("mail: socket() failed"); exit(1); } /* Connect to the SMTP server */ memset(&svr_addr, '\0', sizeof(svr_addr)); svr_addr.sin_family = AF_INET; svr_addr.sin_port = htons(port); svr_addr.sin_addr.s_addr = ip_addr; if (connect(sd, (struct sockaddr*) &svr_addr, sizeof(svr_addr)) != 0) { perror("mail: connect() failed"); exit(1); } response(sd); /********************************************************************/ /* Send the sender info to the server. */ /********************************************************************/ pd = getpwuid(getuid()); rc = sprintf(buffer, "MAIL FROM:%s@", pd->pw_name); gethostname(buffer + rc, DEFAULT_BUF - (rc + 2)); strcat(buffer, "\n"); /* convert to lowercase (after colon) to look right :) */ for(tempptr=buffer+10; *tempptr; tempptr++) *tempptr = tolower(*tempptr); /* Convert to ASCII and send to the server. */ if ((rc = write(sd, EtoA(buffer), strlen(buffer))) < 0) { perror("mail: write() failed sending sender info\n"); close(sd); exit(1); } response(sd); /********************************************************************/ /* Send the recipient name to the server. */ /********************************************************************/ strcpy(buffer, "RCPT TO:"); strcat(buffer, username); strcat(buffer, "\n"); /* Convert to ASCII and send to the server. */ if ((rc = write(sd, EtoA(buffer), strlen(buffer))) < 0) { perror("mail: write() failed sending recipient name\n"); close(sd); exit(1); } response(sd); /********************************************************************/ /* Send the data start marker to the server. */ /********************************************************************/ strcpy(buffer, "DATA\n"); if ((rc = write(sd, EtoA(buffer), strlen(buffer))) < 0) { perror("mail: write() failed sending data start marker\n"); close(sd); exit(1); } response(sd); /********************************************************************/ /* Process input and output between the user and the remote shell. */ /********************************************************************/ #ifdef TESTMSG {char test_msg_str[]="subject:test messge from AS/400\nHave a good day!\n"; write(sd, EtoA(test_msg_str), strlen(test_msg_str)); } #else /* Process data from stdin. */ while (1){ if (gets(buffer) == NULL) break; strcat(buffer, "\n"); buf_size = strlen(buffer); if ((buf_size == 2) && (buffer[0]=='.')) break; /* Convert to ASCII and send to the server. */ if ((rc = write(sd, EtoA(buffer), strlen(buffer))) < 0) { perror("mail: write() failed sending data"); break; } } /* End of while */ #endif /********************************************************************/ /* Send the quit cmd to the server. */ /********************************************************************/ strcpy(buffer, "\n.\nQUIT\n"); /* Convert to ASCII and send to the server. */ if ((rc = write(sd, EtoA(buffer), strlen(buffer))) < 0) { perror("mail: write() failed sending quit cmd\n"); } response(sd); close(sd); exit(0); } /* End of main() */ /* * Signal handler. */ void MySignalHandler(int signo) { switch (signo) { case SIGINT: fprintf(stderr, "\nmail: program ending by SIGINT\n"); exit(0); break; default: exit(1); break; } /* End of switch */ return; } /* End of MySignalHandler() */ /* * Display usage message. */ void usage(void) { fprintf(stderr, "Usage: mail user[@hostname] [SMTP server] \n"); fprintf(stderr, "Note: default SMTP server is 'mail' \n"); exit(1); } /* End of usage() */ /* * Convert a string from EBCDIC to ASCII. */ char* EtoA(unsigned char* str) { unsigned char *in_str; in_str = str; while(*str) { *str = AsciiTable[*str]; str++; } return in_str; } /* * Convert a string from ASCII to EBCDIC. */ char* AtoE(unsigned char* str) { unsigned char* in_str; in_str = str; while(*str) { *str = EbcdicTable[*str]; str++; } return in_str; } #ifdef DEBUG void response(int sd) { int rc; memset(buffer, 0, DEFAULT_BUF); rc=read(sd, buffer, DEFAULT_BUF); AtoE(buffer); printf("%s", buffer); } #else void response(int sd) { return; } #endif