Direct Threaded Daydreams

Understanding TRS-80 CMD Files

November 8, 2009 · 4 Comments

I’ve recently begun to use TRS-80 Model I emulators to recapture some of the programming experiences of my younger days. The emulator I’m currently using under Windows is trs80gp which can be found here:

http://members.shaw.ca/gp2000/trs80gp.html

I invoke the emulator with the command-line parameters -m1 to force Model I emulation and -na for non-authentic display.

While trs80gp does not support any of the Disk-Operating-Systems of yesteryear, it does provide a menu option that will load /CMD executable files and BASIC files. You really can’t save any information back to the Windows filesystem, but that’s okay. For my purposes, I want to write some programs in a cross-assembler or cross-compiler environment and will just load the files to try them out. At some point, I will either look for or will build a utility that will tokenize a text listing to a BASIC listing so that I can create BASIC programs as well.

My initial goal, however, is to write Z-80 code and run it on the emulator.

My first task was to find a cross-assembler for the Z-80 that would run under Windows. The trs80gp site references ZMac which sounds like a great editor, but it doesn’t appear to compile in its current form under Windows.

I found a utility called Pasmo here:

http://www.arrakis.es/~ninsesabe/pasmo/

Like some of the others I tried, Pasmo basically generates a binary machine-image file. I chose Pasmo because of the -d option which shows an assembly listing on the standard output device.

I would like to be able to package up anything I write into a standard /CMD file so that it can be used with other emulators or on the real hardware itself. In order to do that, I was going to have to determine how to convert a machine-image file into a /CMD file.

As a test program, I would use the example routine I published in my post http://jimlawless.wordpress.com/2009/11/07/learning-z-80-assembly-language-on-the-trs-80/. That routine fills the video memory with the all-white character (191) and then returns.

I have several /CMD images of games that I have on cassette and began looking through them. I could see some control-codes and such, but my initial stab at trying to interpret them was not successful. After a little searching on the web, I found a reference to an article from The LDOS Journal volume 1, issue 4. Tim Mann has copies of this issue and others on his site here:

http://www.tim-mann.org/misosys.html

The article that describes the format is in the column Roy’s Technical Corner.

Roy describes the record formats permissible in a /CMD file. The format is not unlike the binary tag-based system used in the TIFF graphical image file format. The first byte one encounters is a record-type byte. The next byte is a length of bytes that will follow … sort of. The remainder of bytes should match the length specified in the length byte. The next record in sequence should be another record ID / length / payload sequence, but that doesn’t seem to hold true either.

I wrote a short C program readcmd.exe that lists each record in a /CMD file. While number of my /CMD files parsed correctly just fine, some did not.

Roy explains that the 01 record indicates a loadable block of binary data. The length byte in many of my /CMD files was zero, which I correctly assumed would yield a 256-byte block. However some of the /CMD files in my possession use a value of two in the length byte and seem to have a payload bigger than two bytes in length.

The article further explains that each loadable block of data first contains a load-address and states that zero and one are special values that indicate a two-byte load-address will be followed by 254 and 255 bytes of data respectively. The article doesn’t mention the value two, but I assume that since the 01 record will always have a load-address, two bytes will always follow. The values zero, one, and two are then used for machine-images of size 254, 255, and 256 respectively. The value three is a complete mystery to me. I have seen a small block with a length of four and the payload that follows the load-address is four bytes in length. I’ll tinker later and see how the emulators load a record with a length value of three.

I should state that my readcmd program is dependent on the Intel representation of a 16-bit integer ( Least Significant Byte followed by Most Significant Byte ). An unsigned short integer must be 16-bits in width in order for the program below to run correctly.

readcmd.c

// readcmd
// Dump the record information for a TRS-80 /CMD
// executable file
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <stdio.h>

int main(int argc,char **argv) {
   FILE *fp;
   unsigned char buff[258];
   unsigned int len;
   unsigned short address;
	printf("readcmd v1.0 by Jim Lawless\n");
	printf("http://jimlawless.wordpress.com\n\n");
   fp=fopen(argv[1],"rb");
   for(;;) {
      if(!fread(buff,1,1,fp))
         break;
			// record type is "load block"
      if(*buff==1) {
         fread(buff,1,1,fp);

         len=*buff;
				// compensate for special values 0,1, and 2.
         if(len<3)
            len+=256;
				// read 16-bit load-address
         fread(&address,1,2,fp);
         printf("Reading 01 block, addr %x, length = %u.\n",address,len-2);
         fread(buff,1,len-2,fp);
      }
      else
				// record type is "entry address"
      if(*buff==2) {
         fread(buff,1,1,fp);
         len=*buff;
         printf("Reading 02 block length = %u.\n",len);
         fread(&address,1,len,fp);
         printf("Entry point is %d %x\n",address,address);
         break;
      }
      else
			// record type is "load module header"
      if(*buff==5) {
         fread(buff,1,1,fp);
         len=*buff;
         printf("Reading 05 block length = %u.\n",len);
         fread(buff,1,len,fp);
      }
      else {
         printf("Unknown code %u at %lx\n",*buff,ftell(fp)-1L);
         break;
      }
   }
   fclose(fp);
}

I found that after the 02 record is encountered, all kinds of garbage data can follow. I assume that most /CMD loaders halt interpretation of the file after the 02 record is encountered. You’ll notice a break out of the main input loop when readcmd encounters this record.

My readcmd program was able to parse through all of the /CMD files in my possession. Now that I have a way to verify the correctness of a /CMD file, it’s time to try and build my own.

I really can’t remember where the first bytes of free memory really start on a Model I. Address 17129 looks to be the spot where BASIC begins, but I’ve never owned a DOS on a Model I, so I don’t know if that address can change.

I noticed that a lot of the games I have begin at address 6C00H, so I chose that as the starting-address for my program.

Here is the slightly modified source code from my prior post:

fill.asm

    ORG     6c00H
    LD      HL,3C00H ; 15360 in hex
    LD      A, 191
    LD      [HL],A
    LD      DE,3C01H
    LD      BC,1023
    LDIR
    RET

I then assembled it with the command:

pasmo -d fill.asm fill.out

The output from Pasmo is as follows:

		ORG 6C00
6C00:21003C	LD HL, 3C00
6C03:3EBF	LD A, BF
6C05:77		LD (HL), A
6C06:11013C	LD DE, 3C01
6C09:01FF03	LD BC, 03FF
6C0C:EDB0	LDIR
6C0E:C9		RET
Emiting raw binary from 6C00 to 6C0E

My load-module is fifteen bytes in size. I need to create a load-record that accommodates fifteen plus two bytes for the load address. My 01 record will have a length of seventeen ( or 11H ) bytes. Here’s how the 01 record should look in hex:

01 11 00 6C 21 00 3C 3E BF 77 11 01 3C 01 FF 03
ED B0 C9

The total space occupied by the 01 record is nineteen bytes.

I then needed to add a 02 record to state the transfer address of 6C00H:

02 02 00 6C

The total size of the two records is twenty-three (17H) bytes in length.

I manually created the /CMD file using the Windows console DEBUG utility.

debug fill.cmd
e 100  01 11 00 6C 21 00 3C 3E BF 77 11 01 3C 01 FF 03
e 110  ED B0 C9 02 02 00 6C
rcx
17
w
q

I first used readcmd to ascertain that the records looked reasonable:

readcmd fill.cmd

readcmd v1.0 by Jim Lawless
http://jimlawless.wordpress.com

Reading 01 block, addr 6c00, length = 15.
Reading 02 block length = 2.
Entry point is 27648 6c00

I loaded fill.cmd in trs80gp and it correctly filled the screen with whitespace.

I had expected the RET instruction to drop me back into BASIC, but it did not. I’m not sure if that’s an idiosyncrasy of trs80gp or if all emulators and the actual hardware/software will behave in this manner. ( NOTE: after fixing my code to use 1023 bytes to move instead of 4095 as George Phillips, author of trs80gp notes in the comments to the post, I did indeed drop into BASIC, but received a ?SN ERROR message at the prompt. I may try George’s suggestion of JP-ing to 1A19H at a later time. )

In the near future, I will write a program that will convert a larger memory-image file ( such as the one produced by Pasmo ) into a /CMD file.

The source and EXE files for readcmd can be found here, along with the source and /CMD file for the fill program.

http://www.mailsend-online.com/wp/readcmd.zip

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ 4 CommentsCategories: ASM · TRS-80
Tagged: ,

Learning Z-80 Assembly Language on the TRS-80

November 7, 2009 · 1 Comment

My first computer was a second-hand TRS-80 Model I with 16K of RAM and a cassette-recorder for auxiliary storage. I was 17 years old when I received this computer in the Fall of 1982. My goal? Like many kids my age at the time, I had intended to write a video game or two and live happily on the riches that would befall me.

The computer was purchased at an auction and came with a fair amount of books on BASIC including many that just contained BASIC games.

My eldest brother had his own TRS-80, so he let me borrow from his vast library of 80 Micro magazines as well.

My first task was to really try to learn BASIC. I did so by typing in programs from the books and by trying to write my own. I had been familiar with BASIC for a couple of years, but only some of the more simple aspects. I had known that if I wanted to write games, I was going to have to code using some mysterious black art known as machine-language. All of the good games from Big Five seemed to be written in machine-language.

As I kept poring through the backlog of issues of 80 Micro, I learned how to use little machine-language subroutines via the USR() function. In order to execute machine-language from BASIC, you had to first reserve some space at the top of BASIC at the MEMORY SIZE? when the computer powered up. ( Note: there are ways of getting around this that I’ll explain in a future post. ) After that, you had to POKE your machine-language routine into reserved memory a byte at a time. Authors usually placed these bytes in a series of DATA statements and used the READ command to read each one in a loop.

After the subroutine was placed in memory, the last task was to point the USR() function to the routine. The address of the routine had to be broken down into two bytes, the least-significant-byte first. I began to grow comfortable with the conversion routine … dividing by 256 to get the high-byte and taking the remainder to get the low-byte.

I also became very comfortable with hexadecimal notation and conversion to and from decimal notation. The only thing I was really lacking at this point, was learning machine-language itself.

I began reading Hardin Brothers’ 80 Micro column The Next Step. This column was a tutorial on machine-language in a sort of cookbook approach. Brothers would present some sort of a short program in assembly-language ( the human-readable syntax that is then assembled into machine-language. )

Most of his programs were very compact and were wonderful to study. He would present the assembly listing for the machine-language routine complete with hex codes by each mnemonic. I found that by converting those hex codes to decimal, I would see the same numbers in the DATA statements for the BASIC loader for the particular routine.

This revelation enabled me to tinker a little with some of the subroutines presented.

One of the machine-language subroutines that was presented in the Radio Shack Level II BASIC manual was a simple routine that would fill the screen with white space. This was done by storing a character with the ASCII code 191 at each location in the machine’s video memory ( located at locations 15360 to 16383 inclusively. )

To see what the program was doing, the BASIC equivalent was easy enough to understand:

As the program ran, each character position on the screen would fill with a white block:

The equivlent assembly language program usually looked something like this:

    ORG     0H
    LD      HL,3C00H ; 15360 in hex
    LD      A, 191
    LD      [HL],A
    LD      DE,3C01H
    LD      BC,1023
    LDIR
    RET

The first line is the ORiGin directive that tells the assembler ( the program that translates assembly-language to machine-language ) what address we plan on starting at. This little routine is relocatable; it can be placed anywhere in memory because it does not internally depend on addresses within itself.

The major work is performed by a Z-80 instruction called LDIR ( LoaD-Increment-Repeat ). LDIR is a block-memory move command that begins by taking the byte at the address held in the HL register pair and stores it at the address in the DE register pair. Then, it decrements the BC register pair by 1 and if BC is not zero, it will increment HL and DE repeat the load-from-HL / store-at-DE / dec BC operation until BC reaches zero.

This routine uses a trick with overlapping memory locations. Note that HL starts at 3C00H and DE 3C01H. When the second iteration of the LDIR loop commences, the value it reads from 3C01H to store in 3C02H was the same as the one in 3C00H. This trick with the source and destination addresses differing by a byte causes the memory at DE for a length of BC to fill with the first byte specified.

So, this is a quick memory-fill routine.

The assembler’s output of this routine might look like the following:

                ORG 0000
0000:21003C     LD HL, 3C00
0003:3EBF       LD A, BF
0005:77         LD (HL), A
0006:11013C     LD DE, 3C01
0009:01FF03     LD BC, 03FF
000C:EDB0       LDIR
000E:C9         RET

The hex digits to the left of each instruction comprise the instruction and its operands (if any). Note the line LD A, BF. This is the line that loads a character 191 into the A register. I found that I could poke any character I wanted into byte number five of this routine and could fill the screen with that value.

I was slowly making headway to learning assembly language itself as I was beginning to understand that the output of the assembler program was ultimately a binary with a bunch of bytes that the Z-80 processor understood.

As I continued to study examples in 80 Micro, I showed some of these programs to my brother. He brought over a couple of items that he’d gotten at a clearance sale at Radio Shack: The Radio Shack Editor/Assembler on cassette and William Barden Jr’s book “TRS-80 Assembly Language Programming.”

I tried to leap into the middle of the book as I had done when learning BASIC, but failed miserably. I started anew and took it step by step. I finally started getting somewhere.

It took a while, but I was able to separate the pseudo-operation command from the actual Z-80 commands and began to make my own subroutines. I also began to use tricks with the cassette load-module format that I had seen some video games use. I figured out how to auto-start a program ( no need to type in a slash at the SYSTEM prompt), scroll the contents of the screen and blur the video in a manner similar to the effects that began the game Attack Force. I also figured out how to load a message immediately on the screen and that the asterisk that normally flashed during a casette load could be replaced with a character 191 for a more graphical effect.

By the Summer of 1983, my goal was to finally write this game. Alas, I knew nothing about software design. I would design fragments, but I was used to just sloppily coding something together and cajoling it to work. I really didn’t have a game idea. I was just working on different effects and animations and was trying to stitch them together into a game.

Unfortunately, my cassette recorder ( like many ) was unreliable when saving / loading my games. The EDTASM program required one to assemble to cassette, then reload to test. This process took forever. I had found a way to put my program at a high-enough spot in memory that I luckily found a re-entry point for EDTASM, so that once my code was tested, I didn’t have to reload EDTASM … I just entered SYSTEM and then an address ( that now escapes me ) that would leave me back at EDTASM’s ‘*’ prompt with my source-code intact.

I spent many late summer nights working on that code while my TV was affixed on a then-independent cable channel from Kansas City. I coded while listening to the audio for The Three Stooges followed by a mix of Get Smart, Hogan’s Heroes, and similar syndicated television shows from the 1970’s.

As I toiled away, the TRS-80 video games market crashed. New computers were becoming popular as was the Atari 2600 video game console system. If I had finished a game and had tried to market it through Big Five Software ( see http://www.bigfivesoftware.com), chances are they wouldn’t have taken it. Nor would any big-league publisher likely have taken on any new games for the TRS-80.

However, I didn’t finish a game. The slow development cycle and the inability to save reliably ultimately left me no choice but to move on. I had looked at getting an expansion interface so that I could then buy a disk drive and a Disk Operating System to minimize my turnaround time, but those options were costly. More attractive computers with color video and relatively inexpensive disk drive options started to take over the landscape.

Using my knowledge of Z-80 assembly-language, I taught myself 6502 assembly-language on one of the Apple ][’s at school. In the Summer of 1984, I bought a Commodore 64 and 1541 disk drive. My days of hacking the TRS-80 were over.

…almost.

I amassed quite a bit of knowledge in a very short amount of time about that little computer. I had wanted to publish some of the more esoteric things I’d found in a magazine like 80 Micro, but I never did. I have some TRS-80 emulators and am planning on revisiting some of these subjects on this blog in the near future.

Oh, by the way … if you wish to email me nowadays, you can reach me at:

jim@trs-80.com

How cool is that? ;-)

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ 1 CommentCategories: ASM · TRS-80 · Tale Recursion
Tagged: , , ,

My Big Shareware Splash

November 4, 2009 · Leave a Comment

If you peek through the archives of alt.comp.shareware.programmer, you’ll see posts from me in the mid-90’s asking questions from the guys who were actually making money by selling their own software.

In April of 1997, I took the big plunge and unleashed a real product onto the masses by way of the SimTel archive:


Jim Lawless
Apr 23 1997, 1:00 am
Newsgroups: comp.archives.ms-windows.announce
Followup-To: comp.archives.ms-windows.discuss
From: (Jim Lawless)
Date: 1997/04/23
Subject: mailsend.zip – Command-line Internet mailer for Win95/NT

I have uploaded to Simtel.Net:

{URL’s removed}mailsend.zip 109880 bytes

mailsend.zip Command-line Internet mailer for Win95/NT

The Mailsend program is a utility for automating Internet e-mail transfers. Mailsend is run from the Win95 command-line. It allows the user to specify a text file and a recipient. The text file will then be sent to the recipient via Internet mail.

By using mailsend within a batch file, a user can send a single text file to a list of users. This feature makes it a practical tool for automating periodic e-mail transmissions such as electronic magazines or announcements via e-mail.

Shareware. Uploaded by the author.


Humble Beginnings

I was quite energetic about writing and selling my own software in the mid-90’s. Perhaps not as energetic as people who made lots of money, but I put a fair amount of time into the study of people who made money selling products on their own.

In 1997, I happened to be writing a review of the Thompson Automation AWK compiler for an article I had pitched to Dr. Dobbs Journal ( see Examining the TAWK Compiler ). I wrote a small client for the Internet finger protocol to demonstrate the compiler’s versatility. As I was going over the code, I had wondered what it would take to flesh out the finger client a little more to make an SMTP e-mail client.

My first attempt was fruitful. I had a command-line emailer working that would simply send text messages via SMTP mail without a lot of frilly features. I did not initially support attachments or other niceties. I decided to use my new creation, MailSend, as a test to learn more about independent software sales. ( Please note that over the years, a number of command-line emailer products have taken the name MailSend … not just mine. )

I found out how to format the supplementary readme files and metadata files whose origins could be traced back to the download sections of electronic Bulletin-Board Systems. I wrote a license agreement and a liberal support policy. I offered free upgrades for life. That was a huge mistake on my part.

My thinking was that I was going to be constantly evolving the product, so if bugs or defects arose, I would simply ask the client to obtain the free upgrade to see if they could recreate the problem with the newest version. I was concerned about being able to support multiple simultaneous versions.

Another concern I had was that I had written the code in a pretty obscure compiler: TAWK. I had reasoned that the entire command-line compiler and the source code to MailSend fit neatly on one 1.44M floppy disk … so I could carry it around and could recompile it on just about any machine.

After discussing things with the folks on alt.comp.shareware.programmer, I found that many of them took non-traditional approaches to writing their software as well. Some wrote in PowerBASIC, many wrote in Delphi, some in varieties of C/C++. I began to realize that the lone wolf developer needed to leverage whatever they were most comfortable with, as long as the tool itself did not become obsolete.

I priced the software at $10 ( another big mistake ) and made a few announcements here and there on various newgroups and forums.


The Early Sales

I was very happy when the first checks made their way to my mailbox. I was seeing a nice little stream of money for this product, but it wasn’t anywhere near what the professionals on a.c.s.p. were making with their software.

After accepting only checks via mail for quite some time, I received an e-mail from a corporate prospect who asked me if I could accept payment via credit-card. I couldn’t at the time, but I asked him to let me see if I could find a card processor. My first attempt at signing up for a credit-card processor was very painful. I canceled the membership before any payments were processed.

I then signed up for RegSoft ( now a Digital River company. ) Although I seemed to have a gift for making mistakes along the way, signing up with RegSoft was the best decision I had made regarding MailSend. In 24 hours after signing up, they processed two orders for MailSend. Neither of these was from the gentleman who had asked if he could pay with a credit-card.

The registrations were becoming much more frequent than the checks-in-the-mail had been.

My mentors in a.c.s.p. attributed this to impulse buying; It’s easier to procrastinate on a purchase if it takes work ( such as writing out a check, addressing an envelope, …etc. ) If one can simply fill out a web page and receive a product electronically in a short time, chances are greater that the sale will commence.

Sometime around these years, I also began participating in the Euro-Share mail-list. Lots of good conversations went on there. You might Google Euro-share archive if you’d like to see the posts.

I should note that I also added a limiting factor to the trial version of MailSend at this time. One could only send about ten emails using the trial version. After that, they would have to reboot their machine so that they could send another ten. I’ll discuss protection and nagware in a future post.


Rising Sales

I would still refer to the monthly income I was making as hobby-level money, but it was GOOD hobby-level money. I began to grow my stable of products with some smaller utilities. ( Please see Throwaway Software : HangUp and A Command Line Scheduler. )

I had begun to make two-hundred to three-hundred dollars each month most months in the early days. I made a few deals for large site-license purchases of my products for several thousand dollars each. By the time the year 2000 had rolled around, I felt like a true independent software developer, although I didn’t make nearly enough to quit my day-job.


Pricing

One of the things that I had not planned for was the costs of doing business. My registration processor took a percentage of each sale. I bought software tools and libraries. $10 was too low of a price-point. When customers wanted bulk-purchase deals, I had already cut out most of the cost of the product, so I had no place to go.

Several of my customers told me that I wasn’t charging enough and regularly registered two copies for each one they needed.

Heeding some advice, I raised the price to $20. I placed a blurb on my site about the increase, stating that it would occur a couple of months away. I really didn’t see any sort of attempts to license MailSend before the change.

When I finally did change the price, it was a non-event. Customers paid $20 per copy and didn’t quibble a bit, unless they were interested in bulk-purchase discounts. Pricing the product was definitely something I should have given more consideration.


Upgrades

The biggest mistake I made was that I do not charge for upgrades for MailSend. I recently read a quote from Joel Spolsky who stated that nothing affects the sales of their defect-tracking software FogBugz like a new release with new features. Joel’s company ( Fog Creek ) sees more sales from upgrades when the new features are worth having than they do from any form of advertisement or sales event.

I have great plans for MailSend, but for a while, they took a back seat to paying gigs. When offered the chance to consult for a fee, I opted for the money instead of opting to work on my software.

I am going to have to rethink this policy as I still have many plans for MailSend’s future.


How the Dot-Com Crash Affected Me

A lot of things happened during the dot-com crash that adversely affected my sales. A number of sites that fed me customers went out of business. Tech companies seemed to be more frugal in their spending at that time and the popularity of my niche products began to wane.

In yet another mistake, I had ignored my mentors who recommended to all new software authors to secure a domain-name. Well, I didn’t. I had known the founders of my Internet Service Provider, so I decided to just keep my personal URL as the reference point for my software. The ISP ended up selling. The new ISP added a tilde (~) to my home page URL, so all of the links I had spread out among the various Usenet posts and other places were now broken.

I also believe that it’s much easier to send email in modern times. Most modern programming languages provide some type of SMTP interface in their runtime libraries, so my product isn’t quite as sought-after as it used to be.

Also, I face a lot of competition; there are a number of very capable command-line mailers out there. Some are free of charge. Some authors make their source code available via open-source licensing models.

MailSend and my other utilities still provide me with a passive cash-flow, but they don’t generate the revenue that they once did. I learned a lot and have a lot more to learn as I continue to support these products and forge ahead creating new ones.

My stories about these early programs aren’t over, yet. In a future Tale Recursion post, I’ll discuss the somewhat controversial topic of protection-schemes in trial software and will discuss the various techniques I have used.

You may obtain trial versions of MailSend and my other software at: ttp://www.mailsend-online.com

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ Leave a CommentCategories: Tale Recursion
Tagged: ,

Hiding Batch File Console Windows

November 2, 2009 · Leave a Comment

( Please note:The good netizens of the alt.comp.msdos.batch.nt Usenet newsgroup pointed out a few things relating to this post.

A new API function is available for Windows 2000 and up called GetConsoleWindow() that alleviates some of the caption-changing operations that I perform in the code below.

There are other utilities which can perform the “hide” operation in addition to many other helpful windows operations. One such utility is “cmdow” available here: http://commandline.co.uk/cmdow/ )

I used to sell a command-line utility for Windows called RUN-and-HIDE that would launch a batch file in a hidden window. While a number of other scripts became available to do the same thing, I noted that I hadn’t seen any that would hide the window of an already-running console process from within that process’s executing batch file script.

I performed a cursory search this evening to see if a utility was to be found that could hide a running console process. Not only was I not able to find one, but many posts state firmly that unless you launch the console process, one absolutely can not hide it.

…so, let me show you how… ;-)

Most windows are easy enough to hide via the Windows API ShowWindow() function. You pass ShowWindow() a window-handle and a show-mode and the window may display differently. One option for the mode argument allows the window to be hidden. ( We could just as easily minimize the window, maximize it, move it, …etc. if we have the window-handle ).

The trick to obtaining the console window-handle is to set the caption to a unique string, then call the Windows FindWindow() function. We need a unique title because FindWindow() will yield the handle for the first window it finds that matches our criteria.

My code will call getpid() to obtain the current process ID for the running utilty and will use that value with a prefix of HIDECMD_ in the running EXE.

Here is the code:

hidecmd.c

// hidecmd.c
// Hide the current console window for a running batch
// script.
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <windows.h>
#include <stdio.h>
#include <process.h>
#pragma comment(lib,"user32.lib")
int main(int argc,char **argv) {
   int pid;
   char wrk[40];
   char old[256];
   HWND h;
      // get the process ID to use as a unique
      // number
   pid=getpid();
   sprintf(wrk,"HIDECMD_%d",pid);
      // preserve the old console window title
   GetConsoleTitle(old,sizeof(old));
      // replace it with a unique titles
   SetConsoleTitle(wrk);
      // give the system time to change the title
   Sleep(40);

      //.now, find the window handle by title
   h=FindWindow(NULL,wrk);
      // hide the window
   ShowWindow(h,SW_HIDE);
      // replace the old title
   SetConsoleTitle(old);
      // wait just a bit for the update again
   Sleep(40);
}

To use hidecmd, place a call to it early in your batch file. You may see the window blink as it initially displays, then disappears.

hidedemo.bat

hidecmd
dir %windir%
exit

I recommend use of the exit verb to ensure that the batch script terminates.

The source and EXE files for hidecmd can be found here.

http://www.mailsend-online.com/wp/hidecmd.zip

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ Leave a CommentCategories: C · Nonconformity
Tagged: , ,

My Foray into Shareware

October 27, 2009 · 1 Comment

In the early 90’s, I wanted to be an independent software developer. Heck, I wanted to be an indie in the 80’s, too. I just didn’t ever seem to be able to harmonize software I’d written with any kind of a need in the marketplace.

At this time, I was still in the habit of frequenting electronic bulletin-board systems (BBS’s). Although I had picked up this hobby while the venerable Commodore 64 was my computer of choice back in 1984, I primarily frequented bulletin-board systems running on MS-DOS ( often supplemented with Quarterdeck’s DesqView to support multiple incoming calls. )

A few of the BBS’s I was particularly drawn to were running on a nice little system called the Spitfire BBS written in Turbo Pascal by fellow Iowan Mike Woltz under the company name Buffalo Creek Software. Mike was selling this software independently. The sysops loved it. The users loved it. I was very impressed that someone who probably lived just a couple hours away from me was actually selling his own software independently and was obviously picking up some sales in my neck of the woods.

In addition to the BBS software itself, Spitfire was able to host third-party plug-ins called “doors”. Doors were simply external programs that observed a predefined parameter file format which contained information about the current user and such. The door program could then take over the online experience as an extension to the BBS itself.

One of the non-game-oriented doors available for Spitfire was a message-board add-on called CircuitNet. This was a networking plug-in that provided a series of nationwide, special-interest, moderated forums not unlike FidoNet.

Later, Woltz wrote his own add-on for Spitfire called SFNet which ultimately replaced SFNet on the BBS’s I used to frequent.

One of the SFNet nationwide forums was specifically for door program discussion. A number of doors were discussed. Game doors were quite popular. One door author would show up from time to time on the forum and would release some pretty good games as try-before-you-buy shareware. He made what I assume to be a small but nice enough amount of money at it, so I decided to try my hand at writing some software that I felt would be of interest to the Spitfire community.

My first attempt to write and sell my own software using the shareware marketing concept was a program called keymac. Keymac was an MS-DOS TSR ( terminate but stay-resident ) utility that I wrote in assembly language. It ran in the background, intercepting all keystrokes that were gathered via the standard BIOS and DOS API routines and would check for keys that had been defined in a macro file.

The macro file allowed one to cause a single key ( with CTRL, ALT, and SHIFT as modifiers ) to generate multiple virtual keystrokes. One could configure the macro text file so that by pressing F8, the characters for a string such as “Hi, there, friend!” would appear to have been typed at the keyboard.

I wrote this utility because a sysop on one of the Spitfire forums was hoping for some kind of macro facility in the Sysop chat mode so that frequently asked questions and such could be answered with the touch of a single key.

I wrote and tested the program and decided to sell it for three dollars. I thought that I’d be able to sell a couple dozen copies of the software over one of these forums and that really would have been enough sales for me.

I released the utility with no nag-screen nor expiration time-outs nor any limiting features on one of the sysops’ BBS’s and gave them a free copy for hosting it. Then, I announced it on one of the forums.

Another sysop … the one who had wished out loud for a macro feature … tried keymac and thanked me for it … but no payment ever came my way. I was dumbfounded. I had written this utility in some very tricky, very tight code and had gone through some considerable testing to make sure that it worked properly. People were using it but I wasn’t getting rich. I wasn’t getting anything.

One day, I had gotten home from work and was opening my mail when I noticed a personal letter from someone in a distant city that I didn’t know. Sure enough, a check for three dollars and a letter thanking me for the utility were in the envelope.

I ended up calling the guy to thank him and asked him how he used the software. He was just ecstatic about the program. He was a sysop, but he used the software on other computers for his own BBS’ing as a client. He said that he’d found many uses for it outside the realm of telecommunications altogether.

I was very happy. The money wasn’t really the issue. By sending a check, the gentleman had sent me an affirmation that I had written something that he found useful enough to pay me for it. That really made my day.

Inspired by my first sale, I ventured out to write another program for the same community. This time, I decided to write a door program as I thought that by targeting something that the BBS users would want instead of the sysops, I might make more sales.

My door was actually a door utility that ran as part of Spitfire’s scheduled maintenance activities. ( I can’t remember exactly how this worked, but I believe there were batch files that ran nightly that could be customized by the sysops ).

I wrote a little utility that would read the users scores from another door game and would post a message to a specified forum containing the high-score list or something like that. Again, I gave a copy to the sysop for the BBS I visited most often and made an announcement on one of the forums.

This time, I actually think I sold two copies of this utility, again at three dollars each. I was quite happy with that. I didn’t take long to write, except for some work with the sysop to ensure that I was posting the message according to the published data-structures. It took me a bit longer that it might have others because I was writing this utility in C and had to deal with data types specific to Turbo Pascal such as counted-strings/packed-arrays-of-characters; strings with a length byte at the beginning instead of a C-style zero-byte terminator.

I was just happy enough that a couple more people registered in a rather timely manner. However, one of the two had a problem with the program. I ended up spending enough time on a long-distance call to correct the program, that my gross sales for the two copies were eaten.

At that point, I ran out of enthusiasm for publishing much more in this particular genre of software. Soon enough, the Internet became readily available to the public and the BBS’s started to disappear.

From these early experiences, I had found that I needed to strongly consider how to price my products in future attempts at marketing software and also needed to ensure that I had some way to keep my support costs down.

Something that wasn’t quite obvious to me yet was that I was going to have to find a way to ensure that people who had planned to pay but were procrastinating could be nudged into paying in a timely manner.

My next steps into becoming an indie software developer were much more fruitful. I’ll tell you more about those in this Tale Recursion section of my blog soon.

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ 1 CommentCategories: MS-DOS · Tale Recursion
Tagged: , , ,

Shrouding CSharp and Java Source Code with AWK

October 25, 2009 · Leave a Comment

I enjoy tinkering with both Java and C# and publish a lot of my source on this blog under a very liberal open-source license.

I have wondered, however, what I would do if I had to protect a commercial program written in either of the two. The obvious choice would be to purchase a professional obfuscation program that defeats most decompilers. Fair enough. Most of these work on the compiled intermediate code.

What, however, if I just wanted to put some mild protection into the compiled product? The mild protection I refer to would still allow the code to be decompiled back to source form, but the person decompiling would have to work hard to make use of the bulk of the code.

My solution was to try a simple shrouding utility.

Shrouding ( also referred to as fogging ) is a kind of source-level obfuscation that was somewhat popular years ago for C programs sold in source form. The programs would generally compile but would be unreadable enough that they would discourage someone from using portions of unlicensed code in other programs.

A lot of these source-level shroud utilities are language-aware and determine what variables, functions, methods, and classes are locally-scoped. The shroud utility then replaces these with generated identifiers.

Most shrouding utilities go a step further and obfuscate literal strings as well as rewriting flow-control constructs.

All I had intended to do was to change the locally-scoped identifier-names to something that my script generates.

My proof-of-concept is an AWK script called foggy.awk. foggy.awk replaces any identifier it finds beginning with two underscore characters with a new identifier containing the prefix “i_” and a sequentially generated number.

This means that in my code, I have to observe a coding convention. I will have to prefix the name of any identifier that should be shrouded with two underscores.

First, here’s the shrouding script:

foggy.awk

# Foggy.awk
# A source-code shrouding utility.
# Replace any "identifier" beginning with __ with a sequentially-
# numbered new identifier
#
# License: MIT / X11
# Copyright (c) 2009 by James K. Lawless
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
BEGIN {
   legal="abcdefghijklmnopqrstuvwxyz";
   legal=legal "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   legal=legal "_0123456789" ;
   id_counter=0;
   id_list["__"]="__";
}
{
   state=0;
   s="";
   for(i=1;i<=length($0);i++) {
      c=substr($0,i,1);
      if(state==0) {
         if(c=="_") {
            state=1;
         }
         else {
            s=s c;
         }
      }
      else {
         if(state==1) {
            if(c=="_") {
               state=2;
               id="__";
            }
            else {
               s=s "_" c;
               state=0;
            }
         }
         else {
            # state == 2
            if(index(legal,c)<1) {
               if(id_list[id]=="") {
                  tmp_id="i_" id_counter;
                  id_counter++;
                  id_list[id]=tmp_id;
               }
               s=s id_list[id];
                  # decrement the index to forget the current
                  # character we're looking at
               i--;
               state=0;
            }
            else {
               id=id c;
            }
         }
      }
   }
   if(state==0) {
      printf("%s\n",s);
   }
   else {
      if(state==1) {
         printf("%s_\n",s);
      }
      else {
         if(state==2) {
            if(id_list[id]=="") {
               tmp_id="i_" id_counter;
               id_counter++;
               id_list[id]=tmp_id;
            }
            printf("%s%s\n",s,id_list[id]);
         }
      }
   }
}

As a side note, I have compiled the above script with the Thompson Automation AWK (TAWK) compiler for Windows into the exe foggy.exe available in the foggy.zip file referenced at the end of this post.

Unfortunately, TAWK is no longer commercially available. I reviewed this compiler years ago in Dr. Dobbs Journal. ( See Examining the TAWK Compiler, DDJ May ‘97 here: http://www.ddj.com/architect/184410193 …)

I also tested with GNU GAWK for Windows.

I would have preferred to use a regular expression with captured groups, but the AWK tools I have do not support those sorts of regex features. This likely would have been a smaller Perl script, but I wanted to try it in AWK. The necessary parser state transitions didn’t seem to be too deep, so I gave it a go.

To use the above script either type:

gawk -f foggy.awk < inputfle > outputfile

...or, if you're using foggy.exe

foggy.awk < inputfle > outputfile

Let's first take a look at a Java program that now contains shroud-ready identifiers. I took the source from MicroHttp1.java from my post here: http://jimlawless.wordpress.com/2009/08/23/tracing-xslt-with-a-tiny-java-web-server/

// MicroHttp1
// A small , specialized web server in Java
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

import java.io.*;
import java.net.*;
import java.util.Date;

public class MicroHttp1Obf {
   public static void main(String[] __args)
      throws IOException {
      ServerSocket __serv;
      Socket __s;
      String __str;
      PrintWriter __pw;
      BufferedReader __br;
      __serv=new ServerSocket(80);
      System.out.println("Micro HTTP Server v 0.1");
      System.out.println();
      for(;;){
         __s=__serv.accept();
         __br=new BufferedReader(
            new InputStreamReader(
               __s.getInputStream()));
         for(;;) {
            __str=__br.readLine();
            System.out.println(__str);
            if( ! __br.ready())
               break;
         }
         System.out.println();
         __pw=new PrintWriter(
            __s.getOutputStream(), true);

         __pw.print("HTTP 200 OK\r\n");
         __pw.print("Content-type: text/html\r\n\r\n");
         __pw.print("<html><head /><body>");
         __pw.print("Current date/time " + new Date());
         __pw.print("</body></html>");
         __pw.close();
      }
   }
}

Note that I had to change the class definition to what I would be targetting for my output filename, since the main Java class and source filename prefix must match.

There are lots of underscores now in this short script. Here's the shrouded output:

// MicroHttp1
// A small , specialized web server in Java
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

import java.io.*;
import java.net.*;
import java.util.Date;

public class MicroHttp1Obf {
   public static void main(String[] i_0)
      throws IOException {
      ServerSocket i_1;
      Socket i_2;
      String i_3;
      PrintWriter i_4;
      BufferedReader i_5;
      i_1=new ServerSocket(80);
      System.out.println("Micro HTTP Server v 0.1");
      System.out.println();
      for(;;){
         i_2=i_1.accept();
         i_5=new BufferedReader(
            new InputStreamReader(
               i_2.getInputStream()));
         for(;;) {
            i_3=i_5.readLine();
            System.out.println(i_3);
            if( ! i_5.ready())
               break;
         }
         System.out.println();
         i_4=new PrintWriter(
            i_2.getOutputStream(), true);

         i_4.print("HTTP 200 OK\r\n");
         i_4.print("Content-type: text/html\r\n\r\n");
         i_4.print("<html><head /><body>");
         i_4.print("Current date/time " + new Date());
         i_4.print("</body></html>");
         i_4.close();
      }
   }
}

There are really only about five shrouded identifiers in this program. I suppose someone who really wanted to work at it could perform global search-and-replace operations to change them into something meaningful as they analyze the code.

Let's try something a little larger that has more local identifiers. For this next test, I took the C# source code from my command-line Twitter client Twimmando. See: http://jimlawless.wordpress.com/2009/05/24/twimmando-a-command-line-twitter-client/

Here's the shroud-ready source:

// Twimmando - a command-line Twitter client

// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Net;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web;

namespace Twimmando
{

   public enum __RequestMethod
   {
      __Get,
      __Post,
      __Head
   }
   class __Config
   {
      public __RequestMethod __Method;
      public string __Uri;
      public string __UserName;
      public string __Password;
      public string __PostData;
   }

   class __Twimmando
   {
      public static string __Version = "Twimmando v1.01 (obfuscated)";
      public static void Main(string[] __args)
      {
         __Config __config;
         try
         {
            __config=__processCommandLine(__args);
            if(__config.__Uri==null)
               Environment.Exit(1);
            __doHttpRequest(__config);
         }
         catch(Exception e)
         {
            Console.Error.WriteLine(e.ToString());
            Environment.Exit(1);
         }
         Environment.Exit(0);
      }

      public static __Config __processCommandLine(string[] __args)
      {
         int __i;
         __Config __config=new __Config();
         __config.__PostData="";
         __config.__Method=__RequestMethod.__Get;

         for(__i=0;__i<__args.Length;__i++) {
            if(string.Compare(__args[__i],"-head",true)==0) {
               __config.__Method=__RequestMethod.__Head;
            }
            else
            if(string.Compare(__args[__i],"-post",true)==0) {
               __config.__Method=__RequestMethod.__Post;
            }
            else
            if(string.Compare(__args[__i],"-uri",true)==0) {
               __config.__Uri=__args[++__i];
            }
            else
            if(string.Compare(__args[__i],"-u",true)==0) {
               __config.__UserName=__args[++__i];
            }
            else
            if(string.Compare(__args[__i],"-p",true)==0) {
               __config.__Password=__args[++__i];
            }
            else
            if(string.Compare(__args[__i],"-f",true)==0) {
               if(__config.__PostData.Length>0) {
                  __config.__PostData+="&";
               }
               __config.__PostData+=__args[__i+1]+"="+HttpUtility.UrlEncode(__args[__i+2]);
               __i+=2;
            }
         }
         if(__config.__Uri==null) {
            Console.WriteLine(__Twimmando.__Version + "\nby Jim Lawless (@lawlessGuy)");
            Console.WriteLine("Usage:\n\ttwimmando [options]\nWhere options are:");
            Console.WriteLine("   -uri resourceURI   ; such as /statuses/public_timeline.xml");
            Console.WriteLine("   -u username        ; Twitter password");
            Console.WriteLine("   -p password        ; Twitter user name");
            Console.WriteLine("   -head              ; send HTTP HEAD request, default is GET");
            Console.WriteLine("   -post              ; send HTTP POST request, default is GET");
            Console.WriteLine("   -f name value      ; add POST data name/value pair to request");
         }
         return __config;
      }

      public static void __doHttpRequest(__Config __config)
      {

         HttpWebRequest __webRequest;
			HttpWebResponse __webResponse;
         Uri __uri=new Uri("http://twitter.com" + __config.__Uri);
			__webRequest = (HttpWebRequest)HttpWebRequest.Create(__uri);
         if(__config.__Password!=null) {
            __webRequest.Credentials = new NetworkCredential(__config.__UserName, __config.__Password);
         }

	 __webRequest.UserAgent = __Twimmando.__Version;
         if(__config.__Method==__RequestMethod.__Post) {
            __webRequest.Method = "POST";
               // remove Expect header
            __webRequest.ServicePoint.Expect100Continue = false;
            __webRequest.ContentType="application/x-www-form-urlencoded";
            __webRequest.ContentLength = __config.__PostData.Length;
            StreamWriter __sOut=new StreamWriter(__webRequest.GetRequestStream(),System.Text.Encoding.ASCII);
            __sOut.Write(__config.__PostData);
            __sOut.Close();
         }
         else
         if(__config.__Method==__RequestMethod.__Head) {
            __webRequest.Method="HEAD";
         }
	 __webResponse = (HttpWebResponse)__webRequest.GetResponse();
         if(__config.__Method==__RequestMethod.__Head) {
            Console.WriteLine(__webResponse.Headers.ToString());
         }
         else {
            Stream __stream = __webResponse.GetResponseStream();
            StreamReader __streamReader =
               new StreamReader(__stream, Encoding.ASCII);
            Console.WriteLine(__streamReader.ReadToEnd());
         }
         __webResponse.Close();
      }
   }
}

Here's the encoded result:

// Twimmando - a command-line Twitter client

// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Net;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web;

namespace Twimmando
{

   public enum i_0
   {
      i_1,
      i_2,
      i_3
   }
   class i_4
   {
      public i_0 i_5;
      public string i_6;
      public string i_7;
      public string i_8;
      public string i_9;
   }

   class i_10
   {
      public static string i_11 = "Twimmando v1.01 (obfuscated)";
      public static void Main(string[] i_12)
      {
         i_4 i_13;
         try
         {
            i_13=i_14(i_12);
            if(i_13.i_6==null)
               Environment.Exit(1);
            i_15(i_13);
         }
         catch(Exception e)
         {
            Console.Error.WriteLine(e.ToString());
            Environment.Exit(1);
         }
         Environment.Exit(0);
      }

      public static i_4 i_14(string[] i_12)
      {
         int i_16;
         i_4 i_13=new i_4();
         i_13.i_9="";
         i_13.i_5=i_0.i_1;

         for(i_16=0;i_16<i_12.Length;i_16++) {
            if(string.Compare(i_12[i_16],"-head",true)==0) {
               i_13.i_5=i_0.i_3;
            }
            else
            if(string.Compare(i_12[i_16],"-post",true)==0) {
               i_13.i_5=i_0.i_2;
            }
            else
            if(string.Compare(i_12[i_16],"-uri",true)==0) {
               i_13.i_6=i_12[++i_16];
            }
            else
            if(string.Compare(i_12[i_16],"-u",true)==0) {
               i_13.i_7=i_12[++i_16];
            }
            else
            if(string.Compare(i_12[i_16],"-p",true)==0) {
               i_13.i_8=i_12[++i_16];
            }
            else
            if(string.Compare(i_12[i_16],"-f",true)==0) {
               if(i_13.i_9.Length>0) {
                  i_13.i_9+="&";
               }
               i_13.i_9+=i_12[i_16+1]+"="+HttpUtility.UrlEncode(i_12[i_16+2]);
               i_16+=2;
            }
         }
         if(i_13.i_6==null) {
            Console.WriteLine(i_10.i_11 + "\nby Jim Lawless (@lawlessGuy)");
            Console.WriteLine("Usage:\n\ttwimmando [options]\nWhere options are:");
            Console.WriteLine("   -uri resourceURI   ; such as /statuses/public_timeline.xml");
            Console.WriteLine("   -u username        ; Twitter password");
            Console.WriteLine("   -p password        ; Twitter user name");
            Console.WriteLine("   -head              ; send HTTP HEAD request, default is GET");
            Console.WriteLine("   -post              ; send HTTP POST request, default is GET");
            Console.WriteLine("   -f name value      ; add POST data name/value pair to request");
         }
         return i_13;
      }

      public static void i_15(i_4 i_13)
      {

         HttpWebRequest i_17;
			HttpWebResponse i_18;
         Uri i_19=new Uri("http://twitter.com" + i_13.i_6);
			i_17 = (HttpWebRequest)HttpWebRequest.Create(i_19);
         if(i_13.i_8!=null) {
            i_17.Credentials = new NetworkCredential(i_13.i_7, i_13.i_8);
         }

	 i_17.UserAgent = i_10.i_11;
         if(i_13.i_5==i_0.i_2) {
            i_17.Method = "POST";
               // remove Expect header
            i_17.ServicePoint.Expect100Continue = false;
            i_17.ContentType="application/x-www-form-urlencoded";
            i_17.ContentLength = i_13.i_9.Length;
            StreamWriter i_20=new StreamWriter(i_17.GetRequestStream(),System.Text.Encoding.ASCII);
            i_20.Write(i_13.i_9);
            i_20.Close();
         }
         else
         if(i_13.i_5==i_0.i_3) {
            i_17.Method="HEAD";
         }
	 i_18 = (HttpWebResponse)i_17.GetResponse();
         if(i_13.i_5==i_0.i_3) {
            Console.WriteLine(i_18.Headers.ToString());
         }
         else {
            Stream i_21 = i_18.GetResponseStream();
            StreamReader i_22 =
               new StreamReader(i_21, Encoding.ASCII);
            Console.WriteLine(i_22.ReadToEnd());
         }
         i_18.Close();
      }
   }
}

This shrouded program was much more difficult for me to read, as I used some local class definitions and used more local variables and methods than I had used in the sample Java program.

My conclusion?

Well, if I had to employ this method, I think I could grow into learning to deal with the added noise of the extra underscores in the source.

However, I still think that language-aware shrouding utilities would be much less painful to use.

The source and Windows executable file for foggy.awk can be downloaded in a single archive at:
http://www.mailsend-online.com/wp/foggy.zip

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ Leave a CommentCategories: AWK / GAWK · CSharp · Java · Nonconformity
Tagged: , , , , ,

A Data Manipulation Library for TAP

October 24, 2009 · Leave a Comment

I’ve addded the file tap_data.c to the TAP family. ( Please see the kick-off post http://jimlawless.wordpress.com/2009/10/10/tap-a-command-processor-library/ .)

TAP Data exposes the void function tap_data_init(). When called, the function adds fifteen new commands to the initialized TAP interpreter.

The new commands consist of integer math operations, logical and / or / not, basic string manipulation, and simple C-style string comparison.

I have also added the following public functions to tap_core.c/.h

   // global tap error message.
extern char _tap_emsg[1025];

   // display an error message
void tap_error_msg(void);

   // check for the appropriate number of arguments and
   // issue an error message if the criteria isn't met.
int tap_arg_check(int argc,int minargs,int maxargs);

   // Return the current line as a string.
   // Do not modify this string!!!
char *tap_current_line(void) ;

   // Return the current line number.
int tap_current_line_num(void);

I started using the tap_error_msg() method internally in the TAP Core and added the other utility routines to check argument counts uniformly. I exposed two introspective functions ( tap_current_line() and tap_current_line_num() ) in this update.

I believe the combination of the TAP Core library and the TAP Data library causes the initialized interpreter to be categorized as Turing-complete.

Here is an updated interpreter host that includes both TAP core and TAP data. script that exercises the new commands:

tap_test2.c

// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <stdio.h>
#include <stdlib.h>
#include "tap_core.h"
#include "tap_data.h"

  // New commands.

   // Print all of the specified arguments
   // on the console.
static void do_println(int argc,char **argv);

int main(int argc,char **argv) {
   int i;
   if(argc<2) {
      fprintf(stderr,"Syntax:\n\ttap_test2 script_filename\n");
      return 1;
   }
   i=tap_init();
   if(!i) {
      printf("Init error!");
      return 1;
   }

   tap_register_cmd("println",do_println);

      // load the basic data manipulation extensions
   tap_data_init();

   i=tap_load_file(argv[1]);
   if(!i) {
      printf("load error");
      return 1;
   }
   tap_run(0);
   return 0;
}

static void do_println(int argc,char **argv) {
   int i;
   for(i=0;i<argc;i++) {
      printf("%s",argv[i]);
   }
   printf("\n");
}

Here’s a script that will exercise the new TAP commands:

test_2.txt


println "Starting..."
println ""
set $a 2
set $b 3

add $a $b
println "add $a $b => " $retval

sub $a $b
println "sub $a $b => " $retval

mul $a $b
println "mul $a $b => " $retval

mod $a $b
println "mod $a $b => " $retval

println ""

or 0 0
println "or 0 0 => " $retval

or 0 1
println "or 0 1 => " $retval

or 1 0
println "or 1 0 => " $retval

or 1 1
println "or 1 1 => " $retval

println ""

and 0 0
println "and 0 0 => " $retval

and 0 1
println "and 0 1 => " $retval

and 1 0
println "and 1 0 => " $retval

and 1 1
println "and 1 1 => " $retval

println ""

not 1
println "not 1 => " $retval

not 0
println "not 0 => " $retval

println ""

substr "Hello, world!" 7
println 'substr "Hello, world!" 7 => ' $retval

substr "Hello, world!" 7 4
println 'substr "Hello, world!" 7 4 => ' $retval

length "Hello, world!"
println 'length "Hello, world!" => ' $retval

index "Testing" "ing"
println 'index "Testing" "ing" => ' $retval

index "Testing" "ung"
println 'index "Testing" "ung" => ' $retval

ord "A"
println 'ord "A" => ' $retval

ord "a"
println 'ord "a" => ' $retval

chr 97
println "chr 97 => " $retval

strcmp "Yes" "Yes"
println 'strcmp "Yes" "Yes" => ' $retval

strcmp "Yes" "YES"
println 'strcmp "Yes" "YES" => ' $retval

strcmp "YES" "Yes"
println 'strcmp "YES" "Yes" => ' $retval

stricmp "Yes" "YES"
println 'stricmp "Yes" "YES" => ' $retval

The output from the above should read:

Starting...

add $a $b => 5
sub $a $b => -1
mul $a $b => 6
mod $a $b => 2

or 0 0 => 0
or 0 1 => 1
or 1 0 => 1
or 1 1 => 1

and 0 0 => 0
and 0 1 => 0
and 1 0 => 0
and 1 1 => 1

not 1 => 0
not 0 => 1

substr "Hello, world!" 7 => world!
substr "Hello, world!" 7 4 => worl
length "Hello, world!" => 13
index "Testing" "ing" => 4
index "Testing" "ung" => -1
ord "A" => 65
ord "a" => 97
chr 97 => a
strcmp "Yes" "Yes" => 0
strcmp "Yes" "YES" => 1
strcmp "YES" "Yes" => -1
stricmp "Yes" "YES" => 0

The source, executable sample file, and sample script for the TAP Data with the updated TAP Core can be downloaded in a single archive at:
http://www.mailsend-online.com/wp/tapdata.zip

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ Leave a CommentCategories: C · Compilers and Interpreters · TAP Ain't Pretty
Tagged: ,

A TCP Command Line Interface in Rhino JavaScript

October 23, 2009 · Leave a Comment

Several weeks ago, I introduced the first in a series of posts that will explore various Internet protocols using Rhino JavaScript to create the supporting software.

Please see: http://jimlawless.wordpress.com/2009/09/03/internet-protocols-and-rhino-javascript/

In this installment, I want to introduce a small utility that we will use at the beginning of many of these posts as an initial testbed before we attempt to write any scripts. We’ll call this program tcp_cli.js ( or just tcp_cli ).

In tcp_cli, I intend to do these things:

  • Prompt the user for a server name
  • Prompt the user for a port number
  • Connect to the specified service
  • Create a thread that will continuously display any responses from the service
  • In the main thread, wait for console input strings and send them to the service

Since I intend to obtain user input, I need to read from Java’s System.in object. Rhino JS already has a print() function, so I thought I’d make a counterpart function called readLine(). I created the readLine() function in a separate library called readline.js. Please see the source code below:

// Provide a function to read from the Java
// standard input object System.in.
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

importPackage(java.io, java.lang);

var stdin=null;

   // We can't reference System.in because "in"
   // is a JS keyword, so we use the brackets to
   // dereference the "in" member of System.
function readLine() {
   if(stdin==null) {
		stdin=new BufferedReader(
			new InputStreamReader(
				System['in']));
   }
   return stdin.readLine();
}

Note that since in is a JavaScript keyword, I had to look up the property ‘in’ using the square-bracket syntax.

I chose to create a separate thread to monitor the responses we get back from the service to simplify the code at this time. Both of the calls to read data from either the standard console input device or to read data from the socket may block ( or halt processing until a read operation can complete ) which can be a bit unwieldy.

We will effectively have two running threads. One will be polling the service we are conversing with and will display that service’s responses. The other thread ( our main thread of execution ) will poll the standard input device and will send those entered strings of text to the service.

Some of you may be asking “Why are you reinventing ‘telnet’ ?”

Telnet is a TCP terminal client that is often used to perform the kinds of exploratory tasks that I intend to introduce in this series of posts. The only drawback to using telnet as a client is that one must type precisely what one intends to type … if you backspace over an error to correct it, the entire stream of characters including backspaces is sent to the service.

The service, more often than not, sees the backspace characters as noise and will yield some sort of error message.

By leveraging the console input device for input, we are afforded the luxury of correcting ourselves as we type before we send anything to the server.

An added bonus is that on many operating-systems, you simply have to press the cursor-up key to scroll through strings that you have already entered. One might find it easier to perform repetitive operations by using this feature.

So, to answer the question, I have not recreated telnet; I have created something similar that allows me to more readily send correct data to the given TCP service.

Here is the source code for tcp_cli:

tcp_cli.js

// TCP session interactive command
// prompt client.
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

importPackage(java.io,java.lang);

load("tcplib.js");
load("readline.js");

   print("What server do you wish to connect to?");
   server=readLine();
   print("What port do you wish to connect to?");
   port=readLine();

   sock=tcpConnect(server,port);
	   // Start a thread to monitor the server's responses
	var mon = new Runnable() {
		run: function () {
         var s;
			for(;;) {
            try {
               if(sock.inp.ready()) {
                  s=sock.inp.readLine();
                  print(s);
               }
            }
            catch(e) {
               print("(monitor is ending...)");
               break;
            }
			}
		}
	};

	new Thread(mon).start();

   for(;;) {
      s=readLine();
      if(s=="alldone")
         break;
      tcpSendStringLine(sock,s);
   }
   tcpClose(sock);

This segment of code may look a little strange:

	var mon = new Runnable() {
		run: function () {
         var s;
			for(;;) {
            try {
               if(sock.inp.ready()) {
                  s=sock.inp.readLine();
                  print(s);
               }
            }
            catch(e) {
               print("(monitor is ending...)");
               break;
            }
			}
		}
	};

	new Thread(mon).start();

The first line instantiates a new Runnable object. Runnable objects are primarily objects capable of being scheduled by the Java thread-manager. When the thread-manager schedules a Runnable object for execution, it ultimately calls that object’s run() method.

We provide a body for the run() method as a JS function. The function loops indefinitely until an exception is thrown. Then, the message (monitor is ending…) is displayed and we drop out of the thread. The monitor thread then ceases execution.

After defining this object, we formally need to instruct the thread-manager to schedule the object for execution. The construction of a Thread object via the new operator followed by a call to that Thread object’s start() method schedules the execution.

We then drop into our console input loop.

Let’s test tcp_cli with the finger server we constructed in the last post. Start the finger server:

java -jar js.jar fingerSrv3.js

In a separate console window, invoke the tcp_cli script:

java -jar js.jar tcp_cli.js

You’ll be prompted for a server and port. Choose localhost and 79 respectively. A connection will then be made. A blank line will appear. You may type a string to send to the service. Enter ‘test’ with no quotes and hit ENTER.

Including the early conversation, you should see something like:

What server do you wish to connect to?
localhost
What port do you wish to connect to?
79
test
Heya! The time is Fri Oct 23 2009 19:55:21 GMT-0500 (CDT)

In the finger server window you should see something like:

test

To terminate tcp_cli enter the string ‘alldone’ in lower-case with no quotes:

alldone

You should then see the “(monitor is ending…)” message.

Now, we have a simple TCP command-line interface. In the next installment, I’d like to explore the POP3 protocol. ( We’ll learn how to read inbound Internet mail from a POP3 provider.)

The source tcp_cli.js can be downloaded at:
http://www.mailsend-online.com/wp/tcp_cli.zip

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ Leave a CommentCategories: Finger · Java · Javascript
Tagged: , , , ,

Preventing Windows Screen-Saver Activation

October 19, 2009 · Leave a Comment

Some time ago, I wanted to see if the simulated mouse moves generated via calls to the WIN32 API mouse_event function would prevent the screen-saver from triggering.

In the current version of XP ( and some older versions of Windows ) these events do indeed keep the screen-saver from activating.

Please refer to the source below.

busy_mouse.c

// Generate mouse events to prevent the screen-saver from
// activating.
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

// check the state of the Scroll Lock or Caps Lock keys.  Return a
// 1 if the requested key is active/on.

#include <windows.h>
#include <stdio.h>
#include <string.h>

#pragma comment(lib,"user32.lib")

void process_messages(void);

int main(int argc,char **argv) {
   int i;
   printf("Busy Mouse v1.0 by Jim Lawless\n");
   printf("If CAPS LOCK is on, the mouse cursor will move around to prevent any screen-savers from activating.\n");
   for(;;) {
      while(GetKeyState(VK_CAPITAL)&1) {
         for(i=0;i<50;i+=2) {
            mouse_event( MOUSEEVENTF_MOVE,2,0,0,0 );
            process_messages();
         }
         Sleep(200);

         for(i=0;i<50;i+=2) {
            mouse_event( MOUSEEVENTF_MOVE,0,2,0,0 );
            process_messages();
         }
         Sleep(200);

         for(i=0;i<50;i+=2) {
            mouse_event( MOUSEEVENTF_MOVE,-2,0,0,0 );
            process_messages();
         }
         Sleep(200);

         for(i=0;i<50;i+=2) {
            mouse_event( MOUSEEVENTF_MOVE,0,-2,0,0 );
            process_messages();
         }
         Sleep(200);
      }
   }
   processMessages();
}

void process_messages(void) {
	MSG m;
	while( PeekMessage(&m,0,0,0,PM_REMOVE)) {
   	TranslateMessage(&m);
		DispatchMessage(&m);
	}
}

When you run busy_mouse.exe the program will loop indefinitely. The program checks the CAPS LOCK state. If CAPS LOCK is enabled, it will then move the mouse in a rectangular pattern via mouse_event().

When CAPS LOCK is off, the simulated mouse events halt.

I’ve used this to keep the screen visible so that I can watch for emails or processes that run long while I’m away from the mouse and keyboard.

The source and executable file for busy_mouse can be downloaded in a single archive at:
http://www.mailsend-online.com/wp/busy_mouse.zip

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ Leave a CommentCategories: C · Hijinks
Tagged: , ,

Thwarting HTTP Referer Trackbacks

October 14, 2009 · Leave a Comment

Unless you’ve configured your browser with privacy plug-ins, your browser passes the address of the current page to each target link you click in a header known as HTTP_REFERER. “Referer” is spelled incorrectly by convention. It was spelled incorrectly during early designs of the HTTP protocol.

One can easily change their own browser to squelch the transmission of the referer, however visitors on a web site may not take the same precautions. What if you have a very personal blog that has a mix of some personal items that you only want a handful of friends to see along with some fun links to other sites?

Anyone viewing your site might click on a link transmitting your private blog page to the site ( where it might be made public. )

Please try this: click the link below. You should see a reference to this blog page.

ttp://www.mailsend-online.com/wp/referring_page.php

Here’s the PHP code for the page:

referring_page.php

<html><head>
<!-- By Jim Lawless
     This code is in the public domain
-->
<title>Referring Page Check</title></head>
<body>
<P>
Your referring link is:
<?php
   echo "<a href=\"", $_SERVER['HTTP_REFERER'],"\">",$_SERVER['HTTP_REFERER'],"</a>";
?>
<p>
</body></html>

So, if you have a couple dozen people reading your blog, chances are that one of them will click on a link that exposes your blog URL to the outside. Of course, this can be protected by using a login system, but there’s another way that might be just as effective that does not require a client to log in to your system.

Normally, a browser issues an HTTP GET command to retrieve a web page. Any time you type a URL into an address bar or click an anchored link, your browser issues a GET to retrieve the given page.

When forms are filled out, the browser often uses the HTTP POST command ( if specified in the form’s METHOD attribute. ) Fields often are sent in name/value pairs during a POST.

Fields can also be sent during a GET request, but they appear on the URL line itself. Such a line might look like:

http://some.url?parm1=this&parm2=that&parm3=other

These URL’s with the parameters are passed in their entirety in the HTTP_REFERER header during a GET. They also often show up in web server logs. However, fields presented during a POST are not carried in the referer.

If we create a page that only displays the private content if a POST was issued and if a special field contains a certain value, any links that the client clicks on will carry only the URL itself without parameters.

If anyone tries to copy that link into a browser’s address bar or if they are clicking it from some sort of referring-page list, they will run into two problems.

  1. They’re issuing the request using a GET
  2. They will have no idea what the special field is supposed to contain

Please consider the following sample PHP documents: ( the first two are actually pure HTML documents… )

refer1.php

<html><head>
<!-- By Jim Lawless
     This code is in the public domain
-->
<title>Referer test 1</title></head>
<body>
Show referring page:
 <a href="referring_page.php">
 referring_page.php</a>
<p>
Go to lead-in page:
 <a href="refer2.php">
 refer2.php</a>
<p>
</body></html>

refer2.php

<html><head>
<!-- By Jim Lawless
     This code is in the public domain
-->
<title>Referer test 2</title></head>
<body  onload="doit()">
<noscript>
You must enable JavaScript to see this site.
</noscript>
<form ID="myform" NAME="myform"
  ACTION="refer3.php" METHOD="POST">

<input TYPE="hidden" NAME="mycode" VALUE="1234">
</form>

<script TYPE="text/javascript">
   function doit() {
      document.getElementById("myform").submit();
   }
</script>
</body></html>

refer3.php

<html><head>
<!-- By Jim Lawless
     This code is in the public domain
-->
<title>Page 3</title></head>
<body>
<?php
   if(strcmp($_POST["mycode"],"1234")==0) {
?>
<h2>Hey, you can see the good stuff!</h2>
<p>
Try going here:<br />
<a href="referring_page.php">referring_page.php</a>

<?php
   } else {
?>
<h2>Nothing to see here.  Move along.</h2>
<?php
   }
?>
</body></html>

Let’s try out this code. Please click on this link. It should open in a new window, so please adjust your popup-blocking software accordingly.

http://www.mailsend-online.com/wp/refer1.php

Click on the referring_page.php link.

You should see that you had originated from the refer1.php page. Click the link on this page to go back there.

You just backtracked to a calling page by using a referer!

Now, click the refer2.php link.

When you do this, you might note that the URL in your browser’s address bar quickly changes from refer2.php to refer3.php.

If you look at the code in refer2.php, you’ll see that it contains a small JavaScript function that triggers when the onLoad event occurs. This function forces the HTML form on the page to be invoked via a call to submit(). The HTTP method defined in the form is POST. Data will be POSTed to the target refer3.php page.

Once in refer3.php, you’ll note that you can see the message “Hey, you can see the good stuff!”

Examination of the source code to refer3.php shows that we look for a POSTed field called mycode that must have a value of “1234″ or the page will render differently.

Try clicking on the referring_page.php link. You’ll see the reference to refer3.php. Click it.

Now, you should see the message “Nothing to see here. Move along.” Because you issued a GET when you clicked the link, no POST operation occurred. Note the PHP else block toward the bottom of the refer3.php script. This is the block of HTML that is rendered if the page is visited without going through a POST with the special code.

This technique will allow one to display a different page to most casual visitors who happen upon a URL ( including search-engine robots and spiders ) and will allow special visitors who know the URL to a lead-in page ( refer2.php, in our case ) to see special content.

Please note that this hack is just for fun. Although you could use it to supplement a real security system, sensitive data should be handled much more thoroughly than by using the technique above. Security through obscurity isn’t secure.

The technique above might be useful if you’d like to keep stuff out of most prying eyes and search-engines that backtrack through the referer, but it isn’t foolproof. All someone has to do is leak the lead-in page address and then everyone could get in.

del_icio_us Save to del.icio.us
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Unless otherwise noted, all code and text entries are Copyright © 2009 by James K. Lawless

→ Leave a CommentCategories: Hijinks · Nonconformity · PHP
Tagged: , , ,