This is MSMessage.m in view mode; [Download] [Up]
/* $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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.