One half of a Windows Sockets test

This is the client side of a Windows Sockets test in C++.

#ifndef _WINSOCK_TEST_H
#define _WINSOCK_TEST_H

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>

WSADATA wsaData;

int initWinsock();

#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include "winsock_test.h"

int initWinsock()
{
	int iResult;

	puts("initWinsock()");

	if (iResult = WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	printf("WSAStartup(MAKRWORD(2, 2), 0x%x) returned %d\n", &wsaData, iResult);
	return 1
}
#include "winsock_test.h"

#define TCP_SOCKET_PORT 27015
#define TCP_SOCKET_ADDR "127.0.0.1"
#define BUFLEN		512

int client()
{
	int    iResult;
	int    recvbuflen       = DEFAULT_BUFLEN;
	struct addrinfo *result = NULL;
	struct addrinfo *ptr    = NULL,
	struct addrinfo hints;
	char   port[5];
	char   *sendbuf         = "this is a test";
	char   recvbuf[DEFAULT_BUFLEN];

	puts("client()");

	printf("ZeroMemory(0x%x, 0x%x)\n", &hints, sizeof (hints));
	ZeroMemory(&hints, sizeof (hints));
	hints.ai_family   = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	itoa(TCP_SOCKET_PORT, port, 10);
	printf("getaddrinfo(%s, %s, 0x%x, 0x%x)\n", TCP_SOCKET_ADDR, port, &hints, &result);
	if (iResult = getaddrinfo(TCP_SOCKET_ADDR, port, &hints, &result) != 0)
	{
		printf("getaddrinfo(%s, %s, 0x%x, 0x%x) returned %d\n", TCP_SOCKET_ADDR, port, &hints, &result, iResult);
		WSACleanup();
		return 1;
	}

	SOCKET ConnectSocket = INVALID_SOCKET;
	ptr = result;
	puts("socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP)\n");
	if (ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol) == INVALID_SOCKET)
	{
		printf("Error on socket(): %ld\n", WSAGetLastError());
		freeaddrinfo(result);
		WSACleanup();
		return 1;
	}

	puts("connect(ConnectSocket, ptr->ai_addr, (int) ptr->ai_addrlen)\n");
	if (iResult = connect(ConnectSocket, ptr->ai_addr, (int) ptr->ai_addrlen) == SOCKET_ERROR)
	{
		printf("connect(ConnectSocket, ptr->ai_addr, (int) ptr->ai_addrlen) returned %d\n", iResult);
		closesocket(ConnectSocket);
		ConnectSocket = INVALID_SOCKET;
	}

	freeaddrinfo(result);

	if (ConnectSocket == INVALID_SOCKET)
	{
		puts("Socket connection failed.\n");
		WSACleanup();
		return 1;
	}

	printf("send(ConnectSocket, %s, (int) %d, 0)\n", sendbuf, (int) strlen(sendbuf));
	if (iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0) == SOCKET_ERROR)
	{
		printf("send failed: %d\n", WSAGetLastError());
		closesocket(ConnectSocket);
		WSACleanup();
		return 1;
	{

	printf("Bytes sent: %ld\n", iResult);

	puts("shutdown(ConnectSocket, SD_SEND)\n");
	if (iResult = shutdown(ConnectSocket, SD_SEND) == SOCKET_ERROR)
	{
		printf("shutdown failed: %d\n", WSAGetLastError());
		closesocket(ConnectSocket);
		WSACleanup();
		return 1;
	}

	// receive data
	do
	{
		puts("recv(ConnectSocket, recvbuf, recvbuflen, 0)\n");
		iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
		if (iResult > 0)
			printf("Bytes received: %d\n", iResult);
		else if (iResult == 0)
			puts("Connection closed"\n);
		else
			printf("recv failed: %d\n", WSAGetLastError());
	}
	while (iresult > 0);

	// no more data, shut down
	puts("shutdown(ConnectSocket, SD_SEND)\n");
	if (iResult = shutdown(ConnectSocket, SD_SEND) == SOCKET_ERROR)
	{
		printf("shutdown failed: %d\n", WSAGetLastError());
		closesocket(ConnectSocket);
		WSACleanup();
		return 1;
	}

	closesocket(ConnectSocket);
	WSACleanup();
	return 0;
}

Quote Database Screen Scraper

I wanted to make fortune(6) cookie files out of the major internet quote databases. So I came up with a Bash script that uses lynx and sed to do it. It includes throttling by default because it’s not nice to suck up all the site’s bandwidth.

#!/bin/bash
# Scrapes a qdb and dumps output to a file
# and tokenizes it into a fortune cookie file
#
LYNX="/usr/bin/lynx"
DEFSLEEP="30"
PNUM_DELIM="%pnum%"

# parse command line args
# look for -s to specify sleep_int period
# look for -p to specify number of pages
# treat everything else like a URL
# %pnum% is page number delimiter
sleep_int=$DEFSLEEP
URLS=()
ARGV=("$@")
for (( thisarg = 0; thisarg < ${#ARGV[*]}; thisarg++ ))
do
	arg="${ARGV[$thisarg]}"
	if [ "$arg" = "-s" ]
	then
		thisarg=$(( $thisarg + 1 ))
		sleep_int=${ARGV[$thisarg]}
	elif [ "$arg" = "-p" ]
	then
		thisarg=$(( $thisarg + 1 ))
		pages=${ARGV[$thisarg]}
	else
		URLS=("${URLS[@]}" "$arg")
	fi
done

LYNXOPTS="-accept_all_cookies -assume_charset=iso-88591 -nolist -dump"

# debug
echo ${URLS[@]}
echo "Sleep is $sleep_int"

for url in "$URLS"
do
	name=`echo $url | cut -d / -f 3`
	mkdir "$name"

	for (( page = 1; page <= $pages; page++ ))
	do
		n_url=`echo $url | sed -e "s/$PNUM_DELIM/$page/g"`
		# debug
		echo "$LYNX $LYNXOPTS $n_url > $name/page_$page"
		$LYNX $LYNXOPTS $n_url > $name/page_$page
		sleep $sleep_int
	done

	# postprocess scraped text files
	cd "$name"

	# remove quote IDs and put in fortune delimiters
	for file in *
	do
		sed -e "s/^\s*#.*$/%/g" < "$file" >> "$name.txt"
	done

	# remove page navigation links
	sed -e "s/^.*[1-9][0-9]* of [1-9][0-9]*.*$//g" < "$name.txt" > "$name"

	# make the database
	strfile "$name"
	rm "$name.txt"

done

Quick ‘n dirty anagrammer using the Internet Anagram Server

I was bored one day and noticed that the an(6) program wasn’t in Red Hat’s repos. So I wrote a Perl script to talk to the Internet Anagram Server’s HTTP interface:

#!/usr/bin/perl
use strict;
use warnings;

use HTTP::Client;
use URI::Escape;

my $client   = HTTP::Client->new();
my $string   = uri_escape(join(" ", @ARGV));
my $document = $client->get("http://www.wordsmith.org/anagram/anagram.cgi?anagram=" . $string . "&t=1000&a=n");
my $start    = index($document, "Anagrams for: $string</h3>");
my $end      = index($document, '<bottomlinks>');
my $relevant = substr($document, $start, ($end - $start));
$relevant    =~ s/<.*>//g;
print $relevant;

aliases-request.pl

A short Perl script I wrote that responds to e-mails with the excerpts of /etc/aliases relevant to the domain to which the request was addressed.

#!/usr/bin/perl
use strict;
use warnings;

# aliases-request.pl
# Returns the relevant parts of /etc/aliases (or specified file)
# Delimited by the requested domain
# ##aliases-request@<domain>
# ##aliases-end@<domain>
#

use constant ALIASES => "/etc/aliases";

# save and parse message
local $/ = undef;    # clear line-ending string
my $msg      = <>;                    # slurp in message
my $domain   = "";
my $dumpfile = "/var/tmp/dumpfile";
open( DUMPFILE, ">$dumpfile" ) or die $!;

# slurp in aliases
open( FILE, ALIASES ) or die $!;
my $aliases = <FILE>;
close FILE;

# reset line-ending string
local $/ = '\n';

for ( split /^/, $msg ) {

    # extract To: domain
    if ( $_ =~ m/^To:.*@(.*)(?:\s|$)/ ) {
        $domain = $1;
        print DUMPFILE "To: Matched " . length(@-) . " items.\n";
        print DUMPFILE "\$domain = $domain\n";
    }

    if ( $_ =~ m/^From:\s+(.*)$/ ) {
        print DUMPFILE "From: Matched " . length(@-) . " items.\n";
        $return_address = $1;
        print DUMPFILE "\$return_address = $return_address\n";
    }

    if ( $_ =~ m/^Reply-to:\s+(.*)$/ ) {
        print DUMPFILE "Reply-to: Matched " . length(@-) . " items.\n";
        $return_address = $1;
        print DUMPFILE "\$return_address = $return_address\n";
    }

    if ( $_ =~ m/^Subject:\s+(.*)$/ ) {
        print DUMPFILE "Subject: Matched " . length(@-) . " items.\n";
        $subject = $1;
        print DUMPFILE "\$subject = $subject\n";
    }
}

# find delimiters and extract relevant chunk
my $delim_string   = "##aliases-request\@$domain";
my $delim_end      = "##aliases-end\@$domain";
my $start_index    = ( index $aliases, $delim_string ) + length($delim_string);
my $end_index      = index $aliases, $delim_end;
my $offset         = $end_index - $start_index;
my $relevant_chunk = substr $aliases, $start_index, $offset;

# create return mail
my $return_address = "";
my $subject        = "";
my $sendmail       = "/usr/sbin/sendmail -t";
my $reply_to = "Reply-to: mailer-daemon\@kitesfear.lakemasoniccenter.org\n";
$subject = "Subject: RE: $subject\n";
my $from = "From: " . "mailer-daemon\@kitesfear.lakemasoniccenter.org\n";
my $to   = "To: " . "$return_address\n";

print DUMPFILE $reply_to;
print DUMPFILE $subject;
print DUMPFILE $from;
print DUMPFILE $to;
print DUMPFILE "Content-type: text/plain\n\n";    # Don't forget extra \n!
print DUMPFILE "$relevant_chunk\n\n.\n";
close(DUMPFILE);

open( SENDMAIL, "|$sendmail" ) or die $!;
print SENDMAIL $reply_to;
print SENDMAIL $subject;
print SENDMAIL $from;
print SENDMAIL $to;
print SENDMAIL "Content-type: text/plain\n\n";    # Don't forget extra \n!
print SENDMAIL "$relevant_chunk\n\n.\n";
close(SENDMAIL);