home *** CD-ROM | disk | FTP | other *** search
- /*
- $Id: MSMessage.m,v 3.1 1997/10/27 11:22:42 lukeh Exp $
-
- Copyright (c) 1996, 1997 Luke Howard.
- All rights reserved.
-
- Portions Copyright (C) 1993 Zik Saleeba <zik@zikzak.net>
- Portions Copyright (C) 1993 Andrew Herbert <andrew@mira.net.au>
- Portions Copyright (C) 1992 Sun Microsystems. Inc.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by Luke Howard.
- 4. The name of the other may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY LUKE HOWARD ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL LUKE HOWARD BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- */
-
- #import <Foundation/Foundation.h>
-
- #import "MSMessage.h"
-
- #ifdef NeXT
- #import <libc.h>
- #import <sys/types.h>
- #import <sys/time.h>
- #import <sys/stat.h>
- #import <sys/socket.h>
- #import <netinet/in.h>
- #import <net/if.h>
- #import <arpa/inet.h>
- #import <netdb.h>
- #import <stdio.h>
- #import <fcntl.h>
- #import <string.h>
- #import <signal.h>
- #import <ctype.h>
- #import <unistd.h>
- #import <pwd.h>
- #import <sys/param.h>
- #import <errno.h>
- #import <stdarg.h>
- #endif
-
- #import <msend.h>
-
- #ifdef NeXT
- char *strdup(const char *str);
- #endif
-
- static char *empty_arg = "";
- static id logDelegate = nil;
-
- void mslog(char *message, ...);
-
- void mslog(char *message, ...)
- {
- NSString *string;
- va_list ap;
-
- va_start(ap, message);
- if (errno && errno != ENOENT) {
- string = [[NSString alloc] initWithFormat:[NSString stringWithFormat:@"%s: %s", message, strerror(errno)] arguments:ap];
- } else {
- string = [[NSString alloc] initWithFormat:[NSString stringWithCString:message] arguments:ap];
- }
-
- va_end(ap);
-
- if (logDelegate) {
- [logDelegate log:string];
- } else {
- NSLog(string);
- }
- va_end(ap);
- [string release];
- }
-
- @interface MSMessage (InternalMethods)
- - (BOOL)assembleMessage;
- - (BOOL)udpMsg;
- - (BOOL)tcpMsg;
- @end
-
- @implementation MSMessage
- /* vend a new message object */
- + (MSMessage *)message
- {
- return [[self class] messageTo:nil];
- }
-
- + (MSMessage *)messageTo:(NSString *)recipient
- {
- return [[[self class] alloc] initWithRecipient:recipient];
- }
-
- - init
- {
- return [self initWithRecipient:nil];
- }
-
- - initWithRecipient:(NSString *)recipient
- {
- [super init];
-
- if (recipient != nil)
- [self setRecipient:recipient];
-
- use_tcp = NO;
- broadcasting = NO;
-
- messageBody = [[NSMutableString alloc] init];
-
- retries = 4;
- Sin.sin_family = AF_INET;
-
- errno = 0;
-
- return self;
- }
-
- + (void)setLogDelegate:(id <MSLogging>)delegate
- {
- [delegate retain];
- [logDelegate release];
- logDelegate = delegate;
- }
-
- - (void)log:(NSString *)err
- {
- NSLog(err);
- }
-
- - (void)setPortToDefault
- {
- struct servent *sp;
-
- sp = getservbyname("message", use_tcp ? "tcp" : "udp" );
- if(sp)
- Sin.sin_port = sp->s_port;
- else
- Sin.sin_port = htons(18); /* from the RFC */
- }
-
- - (void)setUseTcp:(BOOL)useTcp
- {
- use_tcp=useTcp;
- }
-
- - (BOOL)useTcp
- {
- return use_tcp;
- }
-
- - (void)dealloc
- {
- if (_recipient_ptr)
- free(_recipient_ptr);
- [messageBody release];
- [super dealloc];
- }
-
- /* accessor methods for the recipient (eg. user@host) */
- - (void)setRecipient:(NSString *)aRecipient
- {
- char local_name[MAXHOSTNAMELEN];
-
- _recipient_ptr = strdup([aRecipient cString]);
-
- /* (almost) verbatim from msend.c */
- host = (char *)strchr(_recipient_ptr, '@');
-
- if (host == NULL)
- host = empty_arg;
- else
- *host++ = '\0';
-
- term = (char *)strchr(_recipient_ptr, ':');
- if(term == NULL)
- term = empty_arg;
- else
- *term++ = '\0';
- if(!strcmp(term, "all")) /* external form is "all" */
- strcpy(term, "*"); /* protocol uses "*" */
-
- user = _recipient_ptr;
-
-
- if (host[0] == '\0')
- {
- gethostname(local_name, sizeof(local_name));
- host = strdup(local_name); /* local_name is local to our stack */
- }
-
- }
-
- - (NSString *)host
- {
- return [NSString stringWithCString:host];
- }
-
- - (NSString *)user
- {
- return [NSString stringWithCString:user];
- }
-
- - (NSString *)term
- {
- return [NSString stringWithCString:term];
- }
-
- - (void)setPort:(short)port
- {
- Sin.sin_port = htons(port);
- }
-
- - (void)setRetries:(int)r
- {
- retries = r;
- }
-
- - (int)retries
- {
- return retries;
- }
-
- - (short)port
- {
- return ntohs(Sin.sin_port);
- }
-
- - (void)setBroadcasting:(BOOL)doBroadcasting
- {
- broadcasting = doBroadcasting;
- }
-
- - (BOOL)broadcasting
- {
- return broadcasting;
- }
-
- - (BOOL)assembleMessage
- {
- const char *msg_text = [messageBody cString];
-
- char linebuff[256];
- char *dp, *lp;
- FILE *sigfile;
- char *signature;
- char *homedir;
- struct passwd *pwd;
- int buflen;
-
- buflen = 1024;
- msg = malloc(buflen);
- if (msg == NULL)
- return NO; /* out of memory */
-
- *msg = 'B'; /* as per RFC */
- msg_len = 1;
-
- filter(user);
- append_buffer(&msg, &buflen, &msg_len, user, 1);
- filter(term);
- append_buffer(&msg, &buflen, &msg_len, term, 1);
-
- if (msg_text)
- do_line(&msg, &buflen, &msg_len, msg_text);
- else
- return NO;
-
- append_buffer(&msg, &buflen, &msg_len, "", 1);
- lp = (char *)getlogin();
- if (lp == NULL || *lp == '\0')
- {
- struct passwd *me;
- me = getpwuid(getuid());
- if (me == NULL)
- return NO; /* memory leak XXX */
- lp = me->pw_name;
- }
-
- append_buffer(&msg, &buflen, &msg_len, lp, 1);
-
- dp = (char *)ttyname(2);
- if (dp == NULL)
- append_buffer(&msg, &buflen, &msg_len, "", 1);
- else
- append_buffer(&msg, &buflen, &msg_len, dp, 1);
-
- sprintf(linebuff, "%ld", time(NULL));
- append_buffer(&msg, &buflen, &msg_len, linebuff, 1);
-
- homedir = (char *)getenv("HOME");
- if (homedir == NULL)
- {
- pwd = (struct passwd *)getpwnam(lp); /* fixed bug in msend.c */
- homedir = pwd->pw_dir;
- }
- sprintf(linebuff, "%s/.msgsig", homedir);
- signature = "";
- sigfile = fopen(linebuff, "r");
- if (sigfile != NULL)
- {
- linebuff[sizeof(linebuff)-1] = '\0';
- if (fgets(linebuff, sizeof(linebuff)-1, sigfile) != NULL) {
- if (linebuff[strlen(linebuff)-1] == '\n')
- linebuff[strlen(linebuff)-1] = '\0';
- filter(linebuff);
- signature = linebuff;
- }
- fclose(sigfile);
- }
-
- append_buffer(&msg, &buflen, &msg_len, signature, 1);
-
- return YES;
- }
-
- - (void)setDebugging:(BOOL)flag
- {
- debug=flag;
- }
-
- - (BOOL)udpMsg
- {
- int r = retries;
- struct sockaddr_in *sp = &Sin;
- int s, delivered = 0;
- struct sockaddr_in SIN;
- fd_set ready;
- struct timeval to;
- int rval, toutwait, i;
-
- if (debug) NSLog(@"invoked udpMsg(...,%d)",r);
-
- r = retries; /* local copy */
-
- if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- mslog("unable to open socket");
- return NO;
- }
-
- if (broadcasting) {
- i = 1;
- if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &i, sizeof i) < 0) {
- mslog("unable to configure socket for broadcast");
- return NO;
- }
- find_broadcast_addresses(s);
- }
-
- SIN.sin_family = AF_INET;
- SIN.sin_addr.s_addr = htonl(INADDR_ANY);
- SIN.sin_port = htons(0);
-
- if(bind(s, (struct sockaddr *)&SIN, sizeof SIN) < 0) {
- mslog("unable to set local socket address");
- return NO;
- }
-
- toutwait = 3; /* starts at 3 secs and backs off by 2 secs every time */
-
- while(r--) {
- if (debug) NSLog(@"sending message...");
- if (broadcasting) {
- for (i = 0; i < if_n; i++){
- if_a[i].sin_port = sp->sin_port;
- if(debug) NSLog(@"sending message to %s",
- inet_ntoa(if_a[i].sin_addr));
- if(sendto(s, msg, msg_len, 0, (struct sockaddr *)&(if_a[i]),
- sizeof if_a[i]) < 0) {
- mslog("unable to send message");
- return NO;
- }
- }
- }
- else {
- if (sendto(s, msg, msg_len, 0, (struct sockaddr *)sp, sizeof(*sp)) < 0) {
- mslog("unable to send message");
- return NO;
- }
- }
- if (r) {
- to.tv_sec = toutwait;
- to.tv_usec = 0;
- FD_ZERO(&ready);
- FD_SET(s, &ready);
- rval = select(20, &ready, (fd_set *)0, (fd_set *)0, &to);
- if (rval < 0)
- NSLog(@"Interrupt");
- if (rval == 1) {
- delivered = 1;
- udp_decode_ack(s);
- break;
- }
- toutwait += 2;
- }
- }
- if (!delivered)
- mslog("Message unacknowledged - may not have been received");
-
- close(s);
- return YES;
-
- }
-
- - (BOOL)tcpMsg
- {
- int s;
- struct sockaddr_in SIN; /* so as not to hide instance var */
- struct sockaddr_in *sp = &Sin;
- char rcvbuf[256];
- int rval;
-
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { return NO; }
-
- SIN.sin_family = AF_INET;
- SIN.sin_addr.s_addr = htonl(INADDR_ANY);
- SIN.sin_port = htons(0);
-
- if(bind(s, (struct sockaddr *)&SIN, sizeof SIN) < 0) {
- mslog("unable to bind local socket address");
- return NO;
- }
-
- if(connect(s, (struct sockaddr *)sp, sizeof(*sp)) < 0) {
- mslog("unable to connect to TCP server");
- return NO;
- }
-
- if(write(s, msg, msg_len) < 0) {
- (void)close(s);
- mslog("unable to send message");
- return NO;
- }
-
- rval = read(s, rcvbuf, sizeof rcvbuf);
- if (rval < 1) {
- close(s);
- mslog("No reply received");
- return NO;
- }
-
- rcvbuf[(rval < sizeof(rcvbuf)) ? rval : sizeof(rcvbuf)-1] = 0;
- if (rcvbuf[0] == '+') {
- if (debug) NSLog(@"Message delivered to recipient (%s)\n", rcvbuf+1);
- return YES;
- }
-
- else if (rcvbuf[0] == '-') {
- mslog("Message wasn't delivered - %s.", rcvbuf+1);
- return NO;
- }
-
- else {
- mslog("Message wasn't delivered");
- return NO;
- }
-
- return NO;
- }
-
- /* accessor methods for the message itself */
- - (void)setMessage:(NSString *)message
- {
- [messageBody setString:message];
- }
-
- - (void)appendMessage:(NSString *)message
- {
- [messageBody appendString:message];
- }
-
- - (NSString *)message
- {
- return messageBody;
- }
-
-
- - (BOOL)ready
- {
- if (host == NULL)
- return NO;
- if (user == NULL)
- return NO;
- if ([messageBody length] == 0)
- return NO;
-
- return YES;
- }
-
- /* post the message */
- - (BOOL)post
- {
- struct hostent *hp;
-
- if ([self ready] == NO)
- return NO;
-
- if (Sin.sin_port == 0)
- [self setPortToDefault];
-
- if (!broadcasting)
- {
- hp = gethostbyname(host);
-
- if (hp == NULL)
- {
- mslog("unknown host: %s", host);
- return NO;
- }
- memcpy((char *)&Sin.sin_addr, (char *)hp->h_addr, hp->h_length);
- }
-
- /* assemble the message */
- if ([self assembleMessage] == NO)
- return NO;
-
-
- if (broadcasting)
- return [self udpMsg];
-
- if (use_tcp)
- if ([self tcpMsg] == NO)
- return NO;
-
- [self udpMsg];
-
- return YES;
-
- }
- @end
-
- #ifdef NeXT
- #if NS_TARGET_MINOR == 1
- char *strdup(const char *str)
- {
- size_t len = strlen(str) + 1;
- char *copy;
-
- copy = (char *)malloc(len);
-
- if (copy == NULL) return NULL;
-
- bcopy(str, copy, len);
-
- return copy;
- }
- #endif
- #endif
-
-