Issue 2-32, August 13, 1997

Be Engineering Insights: Spamming with BeMail

By Robert Polic

"Forget Fen-Phen! Not Weightloss"

"Email Photos to Friends & Family * Display on Website * Save on your Computer!"

"Balding? New Medications Regrow Hair"

"Best Selling Software---Try It FREE!!!"

One of my email addresses have been made public (sold???) and is now in the hands of the 1990s version of the "Snake Oil Salesman." A day doesn't go by where I'm not bombarded with enticing offers to lose weight, regrow my hair, improve my sex life or get rich quick. I've even received solicitations by the companies that create the spamming software, and for a price, I too, can become a spammer.

So it seems that a popular use of a modern day OS is for email spamming, which got me thinking, with the BeOS we have the most modern of modern OSes and yet there is no spamming program. So the point of this newsletter article (besides fulfilling my obligation to provide this week's Insight) is to remedy this situation (for better or worse).

Our "Marketing Tool for the 90s" will build on mail and query features built into the BeOS. For simplicity, our tool will be command line based and will take three arguments: subject; message file path; and the predicate for an address book query.

(What address book you ask? There is a crude version built into the Preview Release; a more fleshed out version will be available with a forthcoming update to the Preview Release).

We start by constructing a BApplication and overriding the ArgvReceived() and ReadyToRun() methods. The ArgvReceived() function does some simple sanity checking of the parameters, opens and buffers the message content, and calls the Spam() function to do the processing. The ReadyToRun() function alerts the user if the application was executed incorrectly and quits the application:

class TSpamApp : public BApplication {

private:

bool      fArgvCalled;

public:

TSpamApp(void);
virtual void  ArgvReceived(int32, char**);
virtual void  ReadyToRun(void);
void      Spam(char*, char*, char*, off_t);
};


TSpamApp::TSpamApp(void)
  : BApplication("application/x-vnd.Be-SPAM")
{
  // init flag that ArgvReceived has been called
  fArgvCalled = FALSE;
}


void TSpamApp::ArgvReceived(int32 argc, char **argv)
{
  char      *message;
  BEntry    entry;
  BFile     file;
  BMessage  msg(B_REFS_RECEIVED);
  off_t     len;
  status_t  result;

  // flag that ArgvReceived has been called
  fArgvCalled = TRUE;

  // make sure we have the right amount of arguments
  if (argc != 4) {
    printf("USAGE: Spam subject path query\n");
    return;
  }

  // try opening message file
  entry.SetTo(argv[2]);
  file.SetTo(&entry, O_RDONLY);
  if (file.InitCheck() != B_NO_ERROR) {
    printf("ERROR: failed to open message file %s
           [0x%.8x]\n", argv[2], file.InitCheck());
    return;
  }

  // buffer message content
  file.GetSize(&len);
  if (!(message = (char *)malloc(len))) {
    printf("ERROR: failed to allocate message buffer
           (need: %Ld)\n", len);
    return;
  }
  file.Read(message, len);

  // start spamming
  Spam(argv[1], argv[3], message, len);
  free(message);
}


void TSpamApp::ReadyToRun(void)
{
  if (!fArgvCalled)
  // we got here because we were dbl-clicked or launched
  // without arguments
    (new BAlert("", "USAGE: Spam subject path query",
                "OK"))->Go();
  PostMessage(B_QUIT_REQUESTED);
}

The Spam() function performs the query that the sucker^H^H^H^H^H^Hrecipient list is generated with. It also calculates how many messages were queued successfully and provides a list of all recipients (using their real names):

void TSpamApp::Spam(char *subject, char *predicate,
                    char *message, off_t len)
{
  char          *name;
  char          *address;
  int32         count = 0;
  BEntry        entry;
  BFile         file;
  BMailMessage  *mail;
  BQuery        query;
  BVolume       vol;
  BVolumeRoster volume;
  attr_info     info;

  // construct new mail message and add our enticing
  // subject and message
  mail = new BMailMessage();
  mail->AddHeaderField(B_MAIL_SUBJECT, subject);
  mail->AddContent(message, len);

  // set up query on boot volume using passed in predicate
  volume.GetBootVolume(&vol);
  query.SetVolume(&vol);
  query.SetPredicate(predicate);

  // start query
  query.Fetch();

  // loop while we have items that match predicate
  while (query.GetNextEntry(&entry) == B_NO_ERROR) {
    file.SetTo(&entry, O_RDONLY);

    // make sure file opens ok and has email attribute
    if ((file.InitCheck() == B_NO_ERROR) &&
       (file.GetAttrInfo("PERSON:email", &info) ==
       B_NO_ERROR) && (info.size > 1)) {

      // create space for email attribute and read it in
      address = (char *)malloc(info.size);
      file.ReadAttr("PERSON:email", B_STRING_TYPE, 0,
        address, info.size);

      // we will use a BCC field since that's what other
      // spammers seem to do. BCC fields are suppressed in
      // the message and are only used for building the
      // recipient list.  The TRUE parameter means to
      // clobber any previous entries set for this field
      mail->AddHeaderField(B_MAIL_BCC, address, TRUE);

      // attempt to queue message
      if (mail->Send(FALSE) == B_NO_ERROR) {
        count++;
        printf("  QUEUED: ");
      }
      else
        printf("  FAILED: ");

      // get recipients real name
      if ((file.GetAttrInfo("PERSON:name", &info)
           == B_NO_ERROR) && (info.size > 1)) {
        name = (char *)malloc(info.size);
        file.ReadAttr("PERSON:name", B_STRING_TYPE, 0,
          name, info.size);
        printf("%s (%s)\n", name, address);
        free(name);
      }
      else
        printf("%s\n", address);
      free(address);
    }
  }
  delete mail;

  // now send all queued mail
  if (count) {
    send_queued_mail();
    printf("Spammed %d suckers\n", count);
  }
  else
    printf("No recipients found\n");
}

And let's not forget the main just for completeness:

int main(void)
{
  TSpamApp  *myApp;

  myApp = new TSpamApp();
  myApp->Run();

  delete myApp;
  return B_NO_ERROR;
}

With this simple application and the following command I can target my message to a specific audience:

$ Spam 'Reduce coding time by two thirds' blatant_lie.txt
       PERSON:group=*bedevtalk*

BeOS Mail Format

The second part of this article will describe the format of an email message generated by the BeOS.

According to RFC822, all email messages are required to have a Date and From field. These fields will be generated automatically if they are not explicitly set (using the AddHeaderField(B_MAIL_DATE, ...) and AddHeaderField(B_MAIL_FROM, ...) functions).

The Date, if not explicitly set, is the time the Kit receives the Send() command. The From field construction is a bit more complicated. It's constructed from fields defined in both the E-mail and Network preference applications:

"Real Name" POP_User_Name@Domain_Name

If "Real Name" is not defined, the "User Name" defined in the Network panel will be substituted. If "Pop User Name" is not defined the Network Host Name will be substituted.

So as you can see, the From field generated may not be the correct address to which incoming mail should be sent, so a Reply To field is provided. If the Reply To field is left blank in the E-mail panel, none will be added (unless the mail client explicitly sets it). If the client explicitly sets a Reply To field, the Kit will use this one instead of the defined one.

The only other field needed to send a message is either a To or Bcc field. If the recipient name is set through the Bcc field, the recipient names are suppressed in the actual message.

The Kit will also add a default X-Mailer field to the header if one hasn't been explicitly set. Any additional header fields can be added using the AddHeaderField() command. There is no checking by the Kit for the validity of these fields.

For non-MIME type messages, a Content-Type field will also be added with the correct text encoding. The text conversion will be done by the Kit when setting the content field. By default the text will be converted to ISO-8859-1. Other conversions can be set with the AddContent() call.

For multi-part messages (enclosures and text with more than one conversion) two additional fields are added to the header: MIME-version field and Content-Type field. The MIME-version is set to "1.0". The Content-Type field is set to "multipart/mixed" and a boundary is defined.

At each boundary point in the message, a Content-Type field will be present. For text sections this is the same for non-MIME messages (including the text conversions). For enclosure sections the Content-Type is the same as the Content-Type defined in the header including a new boundary.

Before we describe an enclosure section we need some background on a BeOS file. For all practical purposes, the BeOS is a forked file system -- meaning that the contents (text, pictures, etc.) of the file is saved in one fork and the attributes (window position, user preferences, etc.) is stored in another fork (or forks).

When sending a BeOS file as an enclosure it's best to keep all forks intact in case the recipient is also using the BeOS. For users of other OSes, they're likely to be interested only in the content portion of the file. To accomplish this the file is broken up into the content part and the attribute part (all attributes are concatenated into this single part) and are nested under their own MIME boundary.

The file content comes first under its own Content-Type header with the type set to the same MIME type of the file followed by the file name. The attribute part comes next with its own Content-Type header set to "application/x-be_attribute" followed by the file name. Both parts are encoded using base64.


News From The Front

By William Adams

So... You've been to the latest BeDC have you? Well, did you see the naked people riding their bicycles in the rain?

I tell you, I've always had a certain amount of fear and trepidation when it comes to travelling to the East coast of the United States. I always thought it was my fear of getting stuck in a snow storm, but now I know the real fear is that there are some real loonies out there! And I lived in Berkeley for several years.

Moving the BeDC to the east caused several of our demos to crash. What an unheard of event. The demo gods definitely were not smiling upon us on the 4th. But, to the credit of the Be OS community, most developers were quite pleased and excited to see the latest and greatest stuffs. If you were there you may have seen Doug Fulton's paper detector sample application, or Jean-Louis' likeness in more than one 3D application. I think the most exciting thing came with Pierre's demo where he did a Jean-Louis head in a temple setting with lots of butterflies flying around. To top this one off, it was accelerated with the 3Dfx chip set, so it was nice, smooth, and fast with nice textures to boot. This was due to the combined efforts of Geoff's glide library support and George being inspired enough to create an accelerated version of the 3D Kit in short order.

Speaking of acceleration, what's all the hullabalu about this 3Dfx chip set anyway? As I've said in the past, this chip set is arguably one of the most popular in PC class boards today. Their relatively low cost and tremendous speed have made them the target of affection for the latest and greatest games on the PC platform, and now the BeOS. So what about acceleration? We have played with Mesa, which is a freely available OpenGL®-like implementation. Brian Paul, the author, will tell you that it's not OpenGL®, is not an OpenGL® licensed product, and it does not necessarily run the OpenGL® conformance test suite. But I use it anyway because it allows us to do accelerated OpenGL® right now today.

Where does that leave our licensed OpenGL® implementation? We are currently working to extend our OpenGL® implementation to make it more easily accept hardware acceleration in the future. Be Inc. is not putting Mesa out as a replacement for our own implementation. In DTS we felt it would be extremely beneficial to have a implementation of OpenGL® that took advantage of hardware acceleration. Mesa is freely available, and it didn't require too much work on our part to make it available. So there you have it. Mesa is available today, our own extensible OpenGL® will be out in the future, with more hardware support following.

How can one describe MacWorld? Well, after 2 days straight of our own conference, head on over to the World Trade Center and do some more time over there. Booth duty is fun. No really. When you're assigned to what we call the "large demo" you get to see massive crowds at every one of your demos. Giving this demo is likened to inciting a riot. You slowly build up from one application to the next, each time running more applications at the same time. In the finale, when you have 4 QuickTime movies playing along, with pulsating 3D objects, CD sound, digitized stereo sound, and DOOM playing in the background, while you're browsing web pages on your desktop...the pulse tends to quicken.

And the most fun of all, once you've shown all this, you look at the crowd with the wry vampire smile and yell at the crowd, "DO YOU WANT TO DO THIS TO YOUR MAC?" and they wildly and desperately respond "YES!!" and they faint to the ground. And the sweetest response you could give, "of course you do, and you can, because today the BeOS is freely available, here, just take this disk and install it on your Mac." They blink a couple of times, and ask how the demo is crippled, and you tell them, no timeout, not limitations, go ahead, take it, the first one's free.

It's also very gratifying to be able to yank people into our booth by showing them third party applications that are actually shipping. This is a big moment in the history of the BeOS. With the exception of LCS and Metrowerks, this is the first time commercial apps are shipping for the BeOS. In our booth we were selling the BeSpecific disk and Audio Elements from Adamation, and Be Basics and BeStudio from BeatWare. Time and again people would ask, how do I do word processing, and I would say, Just buy BeBasics and you're all set. I think the whole community should be grateful to these early developers for making bold moves towards commercial success. When investors and users see that there are companies making a successful go of it commercially, they tend to pay more attention and vote with their own dollars.

So, I went out to dinner with the Adamation crew on one occasion, and it was very interesting. The topics covered in conversation ranged from Cockney Rhymes to sawed off bee bee guns. From Roswell conspiracies, to the domination of a new digital media environment. You simply had to be there to understand why we were all rolling on the floor laughing for 3 hours, but since you probably weren't, suffice it to say, that the BeOS community is a lively and kickin' place, and there's nowhere else I'd rather be at the moment. Besides, I've picked up quite a few CDs of dance music, and I'm anxious to try them out with that nifty Pulsar Application.

See you on the Front.


After MacWorld

By Jean-Louis Gassée

We get many questions, in person or via e-mail, regarding the Microsoft/Apple deal and, of course, I have an opinion, actually more than one. But too much has been written already on the short-term impact, the loaded symbolism of last week's events at Apple. I'm more interested in mulling over the longer-term consequences and, for this, I'd like to see a few more specks of dust settle down. In particular, I'd like to understand the meaning of the unexpected silence on some loaded topics.

As for our little company, we had a great week for one reason: BeOS developers. Monday and Tuesday, August 4th and 5th, we held a Developers' Conference at the Haynes Convention Center, ending with a Masters Awards party at the Boston Computer Museum. Pierre Raynaud-Richard also presided over a 24-hour 3D Kit programming contest.

On a parallel thread, Alex, Wes and I got up at 1:30am Tuesday morning, drove up to New York in the rain, gave an investor presentation, and came back to Boston in time for another early afternoon meeting. We won't do this too often, I hope, but it felt good seeing BeOS applications emerge as we were evangelizing investors.

As reported elsewhere, the Masters Awards generated over 100 submissions and the quality was such that we had some really difficult decisions on our hands. I won't state here what my favorites are, but I can say I'm impressed with the overall quality and creativity, as well as the way they express unique features of our OS, such as the combination of multi-processing and multi-threading, and the resulting agility and bandwidth.

The same is true of the 3D hackfest. With the first release of our 3D Kit, the programming contest provided a test of the expressive power and efficiency of this new addition to the BeOS. The traditional rotating kettle, familiar to OpenGL® programmers, now serves as a mirror for an orbiting cow textured on the fly, inevitably leading to jokes about an impending presentation of the Intel version to Gateway (no such plans at this time).

The conference consisted of technical sessions mixed with demonstrations of new products by BeOS developers anxious to trot their creations before an audience of their peers. This tested our product in places that probably hadn't been touched before—meaning we discovered fresh new bugs and gained a sense of urgency for the search-and-destroy expedition now taking place in our office. The 28,000 copies of the Preview Release we distributed at MacWorld are certain to provide us with more feedback and opportunities to refine our product.

As is now usual, but we don't take it for granted, our Macworld Expo booth was well attended. The Intel BeOS demonstration was received with an open mind (Apple probably helped by committing to Intel versions of Rhapsody), and the performance, even at this early stage, drew positive comments.

The highlight was the presence of BeOS developers—Adamation, Fusion Development, purity, ro design, and TruSpectra—in our booth, with BeatWare in a nearby booth of their own. We now see the beginnings of commercial applications on our platform; some of them were on sale and sold well at the show. I even saw BeOS software, including our $49.95 retail package, sold at the Developer Depot booth in the Apple pavilion.

Just as important, what emerges in common from these new applications is that the BeOS adds one letter to WYSIWYG, the letter N—for NOW. Real-time WYSIWYG, if you will, instead of watching the hourglass icon. This isn't just about getting tasks done faster and more securely; just as important, this is about preventing wait-time from intruding on the flow of creative thoughts. Such a benefit applies beyond multimedia creation: Ask a programmer how s/he feels waiting around for a compile.

This said, we're now in the process of broadcasting a million units of the BeOS for the remainder of this calendar year. My heartfelt thanks to all who helped prepare and deliver last week's events and motivated us to do even better in the future.


BeDevTalk Summary

BeDevTalk is an unmonitored discussion group in which technical information is shared by Be developers and interested parties. In this column, we summarize some of the active threads, listed by their subject lines as they appear, verbatim, in the mail.

To subscribe to BeDevTalk, visit the mailing list page on our web site: http://www.be.com/aboutbe/mailinglists.html.

NEW

Subject: BeOS for Intel!

AKA: BeOS for Inhell
AKA: cross compiling
AKA: Blinking Lights

Lots of comments about the BeOS-on-Intel announcement. Surprisingly (or maybe not—it's a funny world), we didn't hear much "don your garlic necklace, we're going into the crypt" sentiment. In fact, the port to Intel is seen by some as a righteous crusade; as Bryan Copeland put it...

The majority of computer users use Intel technology... which is why I can't wait for Be on Intel... get people off of the Microsoft operating systems...

The main thread concentrated on hardware—which motherboard/chip set configurations will be supported (and when)? Will ADC/DAC users be thrown into the grungy abyss of PC sound cards?

So what about the PPC? A number of listeners insist that the PPC is the superior chip while conceding that unless CHRP solidifies soon, the party is over. Dave Haynie...

It's going to be hard enough a shot against the x86 if Apple grabbed CHRP by the arms, danced the night away, and ended the evening with a big wet smack on the lips and a few copped feels. Without an open PPC market, Apple's doomed...

There was also a small discussion of the merits of fat vs. CPU-specific binaries. Most folks seem to regard fat binaries as unessential at best, and (looking into the future) potentially clumsy since new chips demand more fat. It's felt that since CDs are big enough to accommodate any number of CPU-specific images there's no reason to squish them into a doughy mess. On a related note, cross-compiling is seen as a must.

Re blinking lights: Some developers are already thinking about ways to wedge a BeBox-like LED display into the bezel of a PC clone. (How about an LED server?)

Subject: User-specified Screen Size

Should games (in particular of all types of apps) be more screen-size aware than they are? Some folks think that as we see more wide and arbitrarily deep monitors, a game designer should try to adapt -- perhaps by letting the user decide which screen mode to use. As Marco Nelissen put it...

...if it doesn't find out from the system which modes are actually available, and shows me a list to choose from, then I consider it a poorly written game.

On the other side, we have the "gamewright" attitude, as expressed by Jon Watte (or a good impersonation):

Current games can give you a choice of the screen modes available when they are compiled, and let you choose between them. Once arbitrary-size comes into play, they will not list the new sizes. Big deal. They weren't tested with the new sizes, and weren't designed to work well on the new sizes, so there's no big loss.

There was some pushing and shoving over the design of the (future) API that would support arbitrary depths and sizes.

Subject: BeOS appearance & Replacing the Tracker?

A big question from Graham Gilmore...

How much of the BeOS 'look' is contained in the Tracker? Let's say I wanted to have a completely new look for BeOS ...would this be possible, and where would I find all the stuff that would need replacing?

A number of listeners called in to offer opinions and vote for methodology. Peter Potrebic summarized Be's current thinking (see below).

THE BE LINE: From Peter Potrebic...

The "Look" and "Feel" of the BeOS is defined by both the app_server (the look of windows and scroll bars) and the Interface Kit (everything else). We have several ideas for opening up these parts of the system for customization.

A couple of ideas for customizing app_server windows are...

  • allow components (color, frame, etc.) to be set through a preferences application

  • provide an add_on architecture to define completely new types of windows

Customizations in the Interface Kit could be handled by a "drop in" library that would redefine how things look and feel (e.g. a library that defines a new draw method for the BButton class).

Subject: Restarting the App Server

Is it possible to restart the app_server after it has crashed? You can telnet into your machine and launch the app_server by hand, but it's simpler (and probably safer) to just reboot.

So why does the app_server crash? Is Be trying to fix the problem?

THE BE LINE: Absolutely.

Subject: Accelerated OpenGL®

Does Be *really* have an OpenGL® implementation? A listener phoned in to point out that, strictly speaking, Be has implemented Mesa. Subterfuge? Not really, say many of our listeners—Mesa looks like OpenGL® and quacks like OpenGL®, therefore it *is* OpenGL®. But some folks, Osma Ahvenlampi notably, are not entirely satisfied...

Nothing in Mesa is OpenGL®, even though it might look similar or even identical. Before anything can be called OpenGL®, it is required to be SGI-licensed. Thus, Mesa is not, and never will be, OpenGL®.

The response, as given by Be's Jake Hamby:

In order to be OpenGL®, it is NOT required to be SGI-licensed, it is required to pass the conformance test. Whether we decide to use the SGI sample code, the Mesa code, our own code, or a combination of them, the OpenGL® logo will be your guarantee that it passes the conformance tests, and is therefore, [to] all intents and purposes, OpenGL®.

This didn't comfort Terry Sikes...

...the difference between Mesa and OpenGL® is significant... What version of OpenGL® does Mesa emulate? 1.0? 1.1? What about extensions? ... The best thing (IMO) for Be would be to partner with SGI and provide SGI OpenGL® for Be. The Intel Win32 drivers would probably move to Intel BeOS pretty easily, and from there to PowerPC. Without this, getting hardware 3D support under BeOS will be problematic at best.

Jake Hamby again...

We've already licensed 'real OpenGL®.' However, *nobody* uses the stock SGI sample implementation without extensive optimization... It's reasonable for us to spend extensive effort into tuning, and even replacing large portions of, the SGI sample code to get the best possible performance for our users.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.