• Pete (unregistered)

    X-Mailer: TPS Reporter v 3.x
    That is my favorite part. Is the author an office space fan, or is that coincidence?

  • (cs)

    My favorite part was

    Eighth = Fourth + Third + Ninth + Fifth + Sixth

  • (cs) in reply to Pete

    Actually, Alex is the office space fan.

  • (cs) in reply to Pete
    Anonymous:
    X-Mailer: TPS Reporter v 3.x
    That is my favorite part. Is the author an office space fan,
    or is that coincidence?

    Not the author, just the editor ;-). Good find, though.

    I replace entity/company names when they have no relavence to the example to protect the submitter (and me of course).

  • (cs)


      Response = "" ' Sent response code to blank **IMPORTANT**

    Good God.[:|]

    Is it me or is the Response variable only populated at the end of the WaitFor sub?

    Also, the naming convention of First, Second, etc. is just brilliant....especially when he has to put a comment after he assigns a value to each of those variables to tell us what it is! Um...how about using a descriptive variable name to do that?[:'(]

     

  • Maik (unregistered)

    I like those Chr(32). Why not just insert a blank?

  • Anonymous (unregistered) in reply to Maik

    Anonymous:
    I like those Chr(32). Why not just insert a blank?

    The Chr(32) guarantees a 'lower case space' where a " " can be interpreted as lower or upper case depending on the compiler (for more information see http://www.thedailywtf.com/forums/30836/ShowPost.aspx).

  • (cs) in reply to Maik

    The real WTF is that this code does not put the new cover sheet on the TPS report before it goes out.  Didn't you get that memo?

  • Anonymous (unregistered)

    Is this code public domain?  I would like to use it in my own applications.

  • (cs)

    Ok, I am going to go out on a limb here and expose myself for the doofus that I may very well be.

    When I first started this first job of mine, I did something very similar to the above.  The client wanted their app that I was maintaining to shoot off a confirmation e-mail to their customers whenever one of the users did action X.  Since I was just out of college with no idea how in the hell to send e-mail programmatically using VB 6, I did some research on the subject.  I found several third party controls, but my boss said those were off limits unless we could get the source code.  The only thrid party controls I found with the source code included were too expensive (granted, I didn't have all that much time to look, and maybe I just don't know where to look for such things).  In the process of researching, though, I felt I had gained enough knowledge on the subject to hack something together on my own.  I knew it wouldn't be pretty, but I was pretty sure I could get it to work.

    What I ended up with looks similar to today's WTF, save such charmingly named variables.  The thing is, that was about 9 months ago.  To date, the e-mail functionality of the application, which is used everyday, has yet to cause any problems.  So, finally, my question is what exactly, besides oddly named variables and the like, is the WTF with this code?  I'm not going to defend this code just because it looks like something I've done.  But if what I've done is horribly WTF-ish, I'd like to know so that I won't do it again.

  • (cs) in reply to skicow

    The really sad thing is that this code is so unsurprising to me.

    The 'first, second, third' WTF is a double.  First, use descriptive names.  Secondly, even if that were not applicable: how about an array?

    Stuff like this pisses me off.  People who code like this invariably have delusions of grandeur in respect to their coding abilities.

  • (cs) in reply to UncleMidriff
    UncleMidriff:

    When I first started this first job of mine, I did something very similar to the above.  The client wanted their app that I was maintaining to shoot off a confirmation e-mail to their customers whenever one of the users did action X.  Since I was just out of college with no idea how in the hell to send e-mail programmatically using VB 6, I did some research on the subject.  I found several third party controls, but my boss said those were off limits unless we could get the source code. 

    If that's really the way your boss feels, your boss should be directing you to use Java or something else with tons of open source packages available..

    UncleMidriff:

    What I ended up with looks similar to today's WTF, save such charmingly named variables.  The thing is, that was about 9 months ago.  To date, the e-mail functionality of the application, which is used everyday, has yet to cause any problems.  So, finally, my question is what exactly, besides oddly named variables and the like, is the WTF with this code?  I'm not going to defend this code just because it looks like something I've done.  But if what I've done is horribly WTF-ish, I'd like to know so that I won't do it again.

    To me, it's how utterly unreadable the code is which pretty much comes down to the use of retarded variable names and magic numbers.

  • joejoe (unregistered) in reply to dubwai

    I call bullshit.

    There's nothing in the code to cause "emails to show up hours late" as delays are e-mail server specific. The WTF would be the person submitting it claiming this.

    Also, I've seen this most of this code before freely available while searching for VB SMTP code. I used it, gutted it, and cleaned it up for one of my own projects that sent email on a daily basis for many, many months without fail. The original code is ugly as fuck, yet not WTF worthy.

  • (cs)

    I personally cringe when I see While/Wend used in VB instead of the much more versitile (and better looking IMO) Do/Loop construct.

  • (cs) in reply to joejoe

    @dubwai:

    I agree, but we use Microsoft everything, and that's that. [:^)]  The application which I was modifying was written in VB 6 anyway, and rewriting it in something more open source friendly, though probably a good idea, wasn't feasible at the time.

  • joejoe (unregistered) in reply to dubwai

    I call bullsh*t.

    There's nothing in the code to cause "emails to show up hours late" as delays are e-mail server specific. The WTF would be the person submitting it claiming this.

    Also, I've seen this most of this code before freely available while searching for VB SMTP code. I used it, gutted it, and cleaned it up for one of my own projects that sent email on a daily basis for many, many months without fail. The original code is ugly as f*ck, yet not WTF worthy.

  • (cs) in reply to dubwai

    The variables are precious, as are a few other things in the code, but unless you're a VB guy (which I'm not) I don't know how you would go about performing the tasks that code performs, and so if the WTF is just the variable names this is a very small WTF. How about a sample of how a Real Programmer (tm) would do it in VB so we can all point and laugh?

  • (cs)

    You gotta love the fact that the author misses the whole point of visual basic.

    I wrote the same application in Unix C my softmore year.

  • (cs) in reply to rogthefrog

    I realize this isn't a "Language X sucks! Use language Y!" but the whole "use a _ to span several lines" thing in VB (and absence of terminating semicolon) drives me nuts.

    Never mind me though.

  • (cs) in reply to joejoe
    Anonymous:
    Also, I've seen this most of this code before freely available while searching for VB SMTP code.


    For example http://www.vbcode.com/Asp/showsn.asp?theID=9730 looks a lot like the code above.
  • (cs) in reply to loneprogrammer
    loneprogrammer:
    My favorite part was

    Eighth = Fourth + Third + Ninth + Fifth + Sixth

    Particularly when Fifth isn't assigned a value until a few lines later......

  • Mr Source (unregistered) in reply to UncleMidriff
  • guy who's suffered with Exchange for too long (unregistered)

     Clearly Alex has never used CDO or MAPI, or he'd know that just because they have small APIs, that doesn't mean they're easy to use.. There's an ungodly amount of install/setup weirdnesses you hit with both of them as soon as you try doing real-world stuff with them.

     Sadly, direct SMTP really is, often, the best way to send mail from a system. Then it's just a matter of using a third-party component if you can convince management to pay for one, or if not, you have to write it yourself, and then sending raw SMTP involves code very much like that above..

     -- dan

  • Anonymous (unregistered)

    must be a slow day ...why is this a WTF ?

    the C++ version does the same exact thing ...

  • (cs)

        If InStr(1, ToEmailAddress, ";") > 0 Then
    tmpArr = Split(ToEmailAddress, ";")
    ArrLen = UBound(tmpArr)
    Else
    ReDim tmpArr(0)
    tmpArr(0) = ToEmailAddress
    ArrLen = 0
    End If


    Why not just:
          tmpArr = Split(ToEmailAddress, ";")
    ArrLen = UBound(tmpArr)
    What is the point of fannying about with the InStr?
    ArrLen = 0 if UBound(tmpArr) is 0...
    (At least, it was in a quick VBA test sub I just wrote...)

  • (cs) in reply to rogthefrog
    rogthefrog:

    I realize this isn't a "Language X sucks! Use language Y!" but the whole "use a _ to span several lines" thing in VB (and absence of terminating semicolon) drives me nuts.

    Never mind me though.



    Tell me about it. 
    I switch between projects in VB and C# during the day and I'm always typing a ; at the end of a line in VB.
    And don't get me started on Case Sensitivity!!
  • Anonymous (unregistered) in reply to Sweets

    too bad you failed miserably in Spelling101 ...

  • Matt B (unregistered)

        Eighth = Fourth + Third + Ninth + Fifth + Sixth


    LOL



  • Matt B (unregistered) in reply to UncleMidriff
    UncleMidriff:

    So, finally, my question is what exactly, besides oddly named variables and the like, is the WTF with this code?  I'm not going to defend this code just because it looks like something I've done.  But if what I've done is horribly WTF-ish, I'd like to know so that I won't do it again.



    Besides the names:

    -pausing an arbitrary # of milliseconds while sending the STMP commands, after forcing the entire thread/app to pause waiting for a single response code from the STMP server.
    -The second while loop in the WaitFor "sub" that continually checks a timer for.. no reason
    -using a global variable (Response) where a return value would work
    - the "**IMPORTANT**" comments
  • Jim H (unregistered)

    While it's not a certain WTF, about 99% of "Sleeps" are due to less than complete understanding of the system in use.  There are of course times when Sleep can't be avoided, or is a fine solution to a problem.  But in general code with a lot of sleepy time is symtomatic of something fundementally wrong in the design.

    I've never programmed in VB, do they not have threads?

    I agree with the boss who won't buy third party tools without they come source code.  It's often a WTF to do that IMHO.  It's like paying someone to do your homework, and then letting them turn it in for you without your even seeing it before the teacher.

  • BogusDude (unregistered) in reply to Matt B
    Anonymous:
    UncleMidriff:

    So, finally, my question is what exactly, besides oddly named variables and the like, is the WTF with this code?  I'm not going to defend this code just because it looks like something I've done.  But if what I've done is horribly WTF-ish, I'd like to know so that I won't do it again.



    Besides the names:

    -pausing an arbitrary # of milliseconds while sending the STMP commands, after forcing the entire thread/app to pause waiting for a single response code from the STMP server.
    -The second while loop in the WaitFor "sub" that continually checks a timer for.. no reason
    -using a global variable (Response) where a return value would work
    - the "**IMPORTANT**" comments


    How about always leaving the To header blank ?:
    Fifth = "To:" + Chr(32) + " " + vbCrLf ' Who it going to



  • BogusDude (unregistered) in reply to Jim H
    Anonymous:
    While it's not a certain WTF, about 99% of "Sleeps" are due to less than complete understanding of the system in use.  There are of course times when Sleep can't be avoided, or is a fine solution to a problem.  But in general code with a lot of sleepy time is symtomatic of something fundementally wrong in the design.

    I've never programmed in VB, do they not have threads?


    VB6 and lower had no threads. Also, no semaphores, mutexes, etc. Why do you need them if you don't have threads ?
    That makes sleeping the only solution in this case. DoEvents is sort of like co-operative multi-tasking in VB. You are basically telling the OS to stop executing your thread, let other threads execute and wake you up when it's done (Like Sleep (0).)

    Anyway, this guy is hardly an experienced coder. Even if he had threads, I doubt his implementation would have looked much different.
    The approach is simple and it will work, if coded correctly. It won't be the most efficient, but it's a good intro to sockets and smpt, imho.

  • Lumpio- (unregistered)

    I've never used VB so I might be missing something, but how does the response from the SMTP server magically go into the Response variable? At least I can't see how that could ever work if it didn't.

  • (cs)

    I agree, sometimes there is no substitute for SMTP, sometimes even thats no good.

     

    I had a situation of having to send an email from an excel spreadsheet when being run under Citrix when the citrix environment does not have access to the users exchange server.

    The security environment did not recognise SMTP traffic from any but a small number of HUB servers running unix.

    The final solution was to write code to save the file required, read it back in and encode it as base64, wrap this as a MIME attachement within a multipart MIME body wrapped in an RFC822 complient message. write this out to a file (onto a drive shared via samba from one of the hub email hosts) from there, a CRON perl job picked up the file and forwarded it through SENDMAIL.

    real pain...

    From the code of this SMTP thing, my favourite bits are...

        frmAction.Winsock1.SendData (Eighth + vbCrLf)
          frmAction.Winsock1.SendData (Seventh + vbCrLf)

    and

       Fifth = "To:" + Chr(32) + " " + vbCrLf ' Who it going to

    not only is it sending a blank to address, but the CHR(32) + " " is just wonderful.

     

    you just know it makes sense.

     

  • Kriz (unregistered) in reply to Lumpio-

    Looks like MS Winsock Control is used.

    Winsock triggers an event (DataArrival, iirc) whenever data is ready on your socket. You can then read the data in your event handler (async i/o is great).  

    Now this is the real WTF, since the programmer should have implemented some kind of state machine inside the event handler instead of using all those DoEvents, Sleep and loops. This turns async i/o into sync i/o and blocking the main thread :-(.

    Furthermore the whole SMTP conversation is error prone:

    • Using vbCrLf  can lead to problems since SMTP requires you to send Chr(13) and Chr(10).  vbCrLf  can expand to anything (i.e. 0013 and 0010).
    • Data lines (everything between data and the dot) must be separated by LF (Chr(10), iirc) not CRLF.
    • Max line length is not enforced
    • Headers are not encoded
  • J D (unregistered)

    Considering the configuration nightmare that is Windows + VB + MAPI, I'd rather support an implementation of an SMTP client in VB than try to rely on the libraries. Assuming, of course, the implementation is tidy, organized, and bug-free...

  • (cs) in reply to Kriz
    Anonymous:

    Looks like MS Winsock Control is used.

    Winsock triggers an event (DataArrival, iirc) whenever data is ready on your socket. You can then read the data in your event handler (async i/o is great).  

    Now this is the real WTF, since the programmer should have implemented some kind of state machine inside the event handler instead of using all those DoEvents, Sleep and loops. This turns async i/o into sync i/o and blocking the main thread :-(.

    Furthermore the whole SMTP conversation is error prone:

    • Using vbCrLf  can lead to problems since SMTP requires you to send Chr(13) and Chr(10).  vbCrLf  can expand to anything (i.e. 0013 and 0010).
    • Data lines (everything between data and the dot) must be separated by LF (Chr(10), iirc) not CRLF.
    • Max line length is not enforced
    • Headers are not encoded

     

    Now that I have an ever so slightly greater level of experience compared to when I did something similar to the above WTF, I can see the wisdom it what you are saying.  However, I also know that when I was researching how to do this back then, I think just about every example featured these or similar loops, sleeps, and DoEvents.  That's not really an excuse I guess, but I thought it was worth mentioning.

    Looking back at my code I can see that I used vbCrLf as well.  It's been working well so far, so how exactly can this cause problems?  I remember reading about the need to enforce line lengths, and I sorta did that (I'm getting more and more embarrassed the more I look at my old code), but I don't remember anything about encoding the headers.  If you have the time or the inclination, would you care to explain why that's necessary?

  • Remboooo (unregistered)

      ' Must set local port to 0 (Zero) or you can only send 
    ' 1 e-mail pre program start
    frmAction.Winsock1.LocalPort = 0

    Err. Wait. When the comment is true, this means that it will use a port for each mail sent, and not close it when it's done? That's pretty damn weird. Especially since he's using a single winsock control, so this shouldn't even be happening. Now I'm not a VB expert, so could anyone explain this comment?

  • Justin (unregistered)
  • anonymous (unregistered) in reply to Remboooo
    Anonymous:
      ' Must set local port to 0 (Zero) or you can only send 
    ' 1 e-mail pre program start
    frmAction.Winsock1.LocalPort = 0

    Err. Wait. When the comment is true, this means that it will use a port for each mail sent, and not close it when it's done? That's pretty damn weird. Especially since he's using a single winsock control, so this shouldn't even be happening. Now I'm not a VB expert, so could anyone explain this comment?



    IIRC VB had a problem with its winsock control.  If you set LocalPort to 0 it cleared it, allowing you to continue using it.  Or something like that.
  • Anonymous (unregistered) in reply to guy who's suffered with Exchange for too long

    Sorry, I have to disagree...

    While CDO has its own special "features" that can be a pain, it's not a big deal to install.  I would never even bother with MAPI - it's a complete waste of time and a piece of crap. 

    However, direct SMTP is rarely, if ever, the best way to send mail from a system.  NO ONE ever takes the time to do a complete implementation.  Something like this P.O.S. should be shit-canned from the beginning just by virtue of the fact that it doesn't even begin to implement the minimum RFC's required for a compliant SMTP mailer.  This doesn't do any logging - that's pretty helpful for trouble-shooting, huh?  And here's my personal favorite - no handling of  bounce/undeliverable mail?  So I guess if you happen to send mail to a misconfigured or bogus address, it can just float around trying to get bounced back to you until it finally dies.  There's a fabulous idea! 

    Boss:  I just got off the phone with a customer who claims they never received and email from your system.  What time was it sent?

    Moron Programmer:  I have no idea.  But I'm pretty sure it went out.

    Boss:  Why don't you check the server logs?

    Moron Programmer:  Because there aren't any to check.

    Boss:  Hmmm - well, did you send it to the wrong address?  Did it bounce back?

    Moron Programmer:  I have no idea.  We can only send mail out. 

    Boss:  Um, I think you're fired because you suck as a programmer.

    Moron Programmer:  Good, this place sucks anyway.  I'll take my shitty code somewhere else.  Bye!

  • (cs) in reply to Justin
    Anonymous:


    Wow.  Just.... Wow... It's like... coding melanoma.  Once the cancer spreads there's nothing stopping it from metastasising.

    How much you wanna bet if you outsource your mail client you'll end up having to give it chemotherapy?

  • poser (unregistered) in reply to Anonymous

    Server logs will be on the mail server which handled this message, look there.
    Bounces will be returned to the address in the outgoing header, look there.

  • Kriz (unregistered) in reply to UncleMidriff

    VB is using Unicode, internally. Without proper conversion (to "Ansi"), passing vbCrLf to non-Unicode can lead to problems. VB does this automatically so it should be safe, actually.  This is especially true when using ActiveX-Controls, so no problems here.

    Headers can only use character code 33 to 127. Anything else has to be encoded (quoted printable and the likes). I'm European and therefore I am very aware of this problem (French characters, German umlauts, ... in subjects and to, etc)

     

  • (cs) in reply to Pete

    You think YOU wish there was an easier way? Observe:

    <font size="6"></font><font size="2">      SUBROUTINE DrawMain ()
          INCLUDE 'graphapi.fi'
          INCLUDE 'graph.fi'
          RECORD /videoconfig/ VC     
          INTEGER OLDBK, OLDFG, A, ROWS
          CHARACTER * 32 CONF
          CHARACTER * 64 MSG(1 : 10)
          MSG(1) = 'Sorry, your video card is an unsupported model. :-('
          MSG(2) = 'Sorry, a color monitor is required. :-('
          MSG(3) = 'WARNING!!! UNABLE TO DETECT YOUR VIDEO CARD!!!'
          MSG(4) = 'This could mean nothing, or it could mean that'
          MSG(5) = 'something is very wrong with your system. It also'
          MSG(6) = 'means that the demo has no way of knowing whether'
          MSG(7) = 'or not your display supports the video mode that'
          MSG(8) = 'is required. If you are SURE that there is nothing'
          MSG(9) = 'wrong with your video card and that it does support'
          MSG(10) = '80x43 mode, type run at the following prompt.'
          CALL _getvideoconfig(VC)
          IF ((VC.adapter .EQ. _HERCULES) .OR. (VC.adapter .EQ. _CGA)) THEN
                IF (VC.adapter .EQ. _MDPA) THEN
                    PRINT*, MSG(1)
                    STOP
                END IF
          END IF
          IF ((VC.monitor .EQ. _MONO) .OR. (VC.monitor .EQ. _ANALOGMONO))
         Z THEN
                PRINT*, MSG(2)
          END IF
           IF ((VC.adapter .EQ. _UNKNOWN) .OR.
         Z (VC.adapter .EQ. _NODISPLAY)) THEN
                PRINT*, (MSG(A), A = 3, 10)
                READ*,CONF
                IF ((CONF(1:3) .NE. 'run') .AND. (CONF(1:3) .NE. 'RUN')
         Z .AND. (CONF(1:3) .NE. 'Run') .AND. (CONF(1:3) .NE. 'rUn')
         Z .AND. (CONF(1:3) .NE. 'ruN') .AND. (CONF(1:3) .NE. 'RUn')) THEN
                      IF (CONF(1:3) .NE. 'rUN') STOP
                END IF
          END IF           
          IF ((VC.numtextcols .EQ. 80) .AND. (VC.numtextrows .EQ. 43)) THEN      
                CALL _clearscreen( _GCLEARSCREEN )
          ELSE
                CALL _setvideomode( _TEXTC80 )
                ROWS = _settextrows( 43 )
                IF (ROWS .NE. 43) THEN
                      PRINT*, 'ERROR'
                      STOP
                END IF
          END IF
          OLDBK = _setbkcolor( 4 )
          OLDFG = _settextcolor( 12 )
          CALL _settextwindow(4, 24, 13, 25)
          CALL _settextposition(1, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('**' // CHAR(0))                             
          CALL _settextwindow(4, 26, 5, 30)
          CALL _outtext('****' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('****' // CHAR(0))
          CALL _settextwindow(7, 26, 8, 28)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextwindow(4, 31, 12, 37)
          CALL _settextposition(1, 2)
          CALL _outtext('****' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextwindow(4, 38, 12, 45)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextwindow(4, 45, 12, 52)
          CALL _settextposition(1, 2)
          CALL _outtext('****' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 3)
          CALL _outtext('**' // CHAR(0))
          CALL _settextwindow(4, 52, 12, 59)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextwindow(14, 24, 23, 31)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('****' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('****' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextwindow(14, 31, 23, 37)
          CALL _outtext('*****' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('*****' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 4)
          CALL _outtext('***' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextwindow(14, 38, 23, 45)
          CALL _outtext('*****' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('*****' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 4)
          CALL _outtext('***' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextwindow(14, 45, 23, 52)
          CALL _settextposition(1, 2)
          CALL _outtext('****' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(5, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(9, 2)
          CALL _outtext('****' // CHAR(0))            
          CALL _settextwindow(14, 52, 23, 59)
          CALL _outtext('*****' // CHAR(0))
          CALL _settextposition(2, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(3, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(3, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(4, 1)
          CALL _outtext('******' // CHAR(0))
          CALL _settextposition(5, 1)
          CALL _outtext('*****' // CHAR(0))
          CALL _settextposition(6, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(6, 4)
          CALL _outtext('***' // CHAR(0))
          CALL _settextposition(7, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(7, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(8, 5)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 1)
          CALL _outtext('**' // CHAR(0))
          CALL _settextposition(9, 5)
          CALL _outtext('**' // CHAR(0))   </font>        

    ...and so on for a few more pages.

    Perhaps FORTRAN wasn't the best choice of languages for the task at hand. Try and guess what it draws, no points for actually compiling it. :-(

  • (cs) in reply to poser
    Anonymous:
    Server logs will be on the mail server which handled this message, look there.
    Bounces will be returned to the address in the outgoing header, look there.

    This is the mail server that handled the message. What part of direct SMTP mailer don't you understand? Even if you meant the recipient server, I very much doubt any given company would send its server logs to you for an offhand request. As for bounces returning to sent address, this is assuming the server exists, is up, encounters no errors sending, and your dns isn't on the fritz, any of which are very bold assumptions indeed.

    Remind me to stay away from any network software you make.

    As for VB having no multithreading, I don't know what planet you all live on, but on this one it's had mutithreading since VB5. The functions aren't built into VB, you have to call the kernel, but the runtime is mostly thread-safe. All win32 COM thread features, with the exception of fibers, are available to VB as well. (VB COM threading code looks almost identical to C/C++ win32 COM threading code in fact.)
  • Oliver (unregistered) in reply to UncleMidriff

    > But if what I've done is horribly WTF-ish, I'd like to know so that I won't do it again.

    Ok.

    The code is arguably fine - it probably does its job. It's achillies heel is a dependency on assumption.

    Have you ever done the simple programming exercise, "Write instructions for a robot to make a cup of coffee"? Some people write "turn the kettle on, boil some water, pour water into a mug, add coffee, drink". These people write code like the above WTF.

    What's wrong with those instructions? The robot is stupid.

    Which kettle? What about filling the kettle with water first? And when you say "boil some water" did you mean "with the kettle" or just fire the robots laser beam at the dog's bowl? How about you rinse the three-month old mould out of the mug first? And maybe, just maybe, you ought to wait a few moments before drinking the boiling hot water? :)

    Look back over the code, and look at it in terms of operations. Look at how many lines of code repeat similar operations.

    Every time you repeat a set of operations like that, you introduce an opportunity for errors, you might mistype Chr(23) by mistake on one line, or you might type ";" on one of the header lines.

    If you know that you want to construct a series of lines that consist of <LABEL><COLON><CHR(32)><TEXT><CRLF>- then you've just identified an algorithm. Give it a sensible name and use it. Now you know that when you call CreateHeader(label, text) then as long as CreateHeader works elsewhere, it'll Do The Right Thing.

    Lastly... The author seems to have a size limit on his algorithms. Thinking "this is too short to make a function" is often a false saving.

    The SMTP protocol is essentially a game of chess between two state engines. There is information in the protocol that the above code loses - significantly the distinction between a timeout, a permanent error (rejection by the server) and a transient error such as server busy. More importantly, it is a conversation between disparate processes, and you should never make assumptions when both processes are not entirely under your control, *especially* if a network is involved.

    Because each interaction with the server is hand-written, rather than invoked algorithmically, it would be a chore to, for example, test to see if SendData failed or catch any raise generated by it, so instead he just relies on the timeout.

    Write your code in terms of algorithms first. You can always "manually inline" later. It's a hard thing to teach yourself because we all want to just knock up the code quickly, and somehow writing lots of functions seems the wrong way to go about it. But you'll quickly find the initial your code far less buggy, easier to track the bugs down in, and quicker to reach maturity.

    Think at it this way: write your "main" like a prototype, in terms of algorithms. Do the same for each algorithm, and once you reach the bottom of the stack this way, you'll find each parent function/algorithm almost writes itself, and just a matter of fleshing the functions out.

    http://www.m-w.com/cgi-bin/dictionary?book=Dictionary&va=algorithm

    </LABEL>
  • (cs) in reply to Oliver

    foxyshadis:

    This is the mail server that handled the message. What part of direct SMTP mailer don't you understand? Even if you meant the recipient server, I very much doubt any given company would send its server logs to you for an offhand request. As for bounces returning to sent address, this is assuming the server exists, is up, encounters no errors sending, and your dns isn't on the fritz, any of which are very bold assumptions indeed.

    Remind me to stay away from any network software you make.

    Alright, I just read RFC 821 in its entirety.  In it, I saw nothing about the SMTP sender needing to do anything about mail that the SMTP receiver can't relay other than to provide the SMTP receiver with a reverse path (which this fellow has done).  Now, after reading the RFC, I realize that there are many situations in the dialog between SMTP sender and SMTP receiver that this code should handle more gracefully, but handling bounced e-mail isn't one of those situations as near as I can tell.  Here is how I see the situation.  I'm fully willing to admit that I'm missing something, so by all means correct me if I am wrong:

    This application using this code becomes an SMTP sender to the SMTP receiver indicated by the MailServer variable.  A connection is established.  The sender tells the MailServer that it would like to send a message from <FONT color=#000000>[email protected]</FONT> to <FONT color=#000000>[email protected]</FONT>.  The receiver (MailServer) then sees that the first entry in the forward path (<FONT color=#000000>[email protected]</FONT>) is not istelf, so it assumes that it needs to relay the message on to hotmail.com.  Now it becomes the SMTP sender, connects to hotmail.com, and tries to send a message from MailServer,<FONT color=#000000>[email protected]</FONT> to <FONT color=#000000>[email protected]</FONT>.  Hotmail, which doesn't have a mailbox for a user named MrGuy, tells MailServer to screw off.  It is now MailServer's job to send an "undeliverable mail" notice to the first place indicated in its reverse path for this message, which happens to be <FONT color=#000000>[email protected]</FONT>.  Again acting as SMTP sender, MailServer connects to initech.com and sends the "undeliverable mail" notice to <FONT color=#000000>[email protected]</FONT>.  If initech has a mailbox for a user named MrGuy, great, he gets the "undeliverable mail" notice.  If initech has no such mailbox, it tells MailServer to screw off, at which point MailServer can do whatever the hell it wants to with the message, such as cry about it, I guess.

    Is that about right, or am I missing something?

    Anonymous:

    > But if what I've done is horribly WTF-ish, I'd like to know so that I won't do it again.

    Ok.

    The code is arguably fine - it probably does its job. It's achillies heel is a dependency on assumption.

    Have you ever done the simple programming exercise, "Write instructions for a robot to make a cup of coffee"? Some people write "turn the kettle on, boil some water, pour water into a mug, add coffee, drink". These people write code like the above WTF.

    What's wrong with those instructions? The robot is stupid.

    Which kettle? What about filling the kettle with water first? And when you say "boil some water" did you mean "with the kettle" or just fire the robots laser beam at the dog's bowl? How about you rinse the three-month old mould out of the mug first? And maybe, just maybe, you ought to wait a few moments before drinking the boiling hot water? :)

    Look back over the code, and look at it in terms of operations. Look at how many lines of code repeat similar operations.

    Every time you repeat a set of operations like that, you introduce an opportunity for errors, you might mistype Chr(23) by mistake on one line, or you might type ";" on one of the header lines.

    If you know that you want to construct a series of lines that consist of <LABEL><COLON><CHR(32)><TEXT><CRLF>- then you've just identified an algorithm. Give it a sensible name and use it. Now you know that when you call CreateHeader(label, text) then as long as CreateHeader works elsewhere, it'll Do The Right Thing.

    Lastly... The author seems to have a size limit on his algorithms. Thinking "this is too short to make a function" is often a false saving.

    The SMTP protocol is essentially a game of chess between two state engines. There is information in the protocol that the above code loses - significantly the distinction between a timeout, a permanent error (rejection by the server) and a transient error such as server busy. More importantly, it is a conversation between disparate processes, and you should never make assumptions when both processes are not entirely under your control, *especially* if a network is involved.

    Because each interaction with the server is hand-written, rather than invoked algorithmically, it would be a chore to, for example, test to see if SendData failed or catch any raise generated by it, so instead he just relies on the timeout.

    Write your code in terms of algorithms first. You can always "manually inline" later. It's a hard thing to teach yourself because we all want to just knock up the code quickly, and somehow writing lots of functions seems the wrong way to go about it. But you'll quickly find the initial your code far less buggy, easier to track the bugs down in, and quicker to reach maturity.

    Think at it this way: write your "main" like a prototype, in terms of algorithms. Do the same for each algorithm, and once you reach the bottom of the stack this way, you'll find each parent function/algorithm almost writes itself, and just a matter of fleshing the functions out.

    http://www.m-w.com/cgi-bin/dictionary?book=Dictionary&va=algorithm

    </LABEL>

    Very good advice.  It's stuff I already know but sometimes have a hard time being disciplined enough to follow as closely as I should.

  • (cs) in reply to UncleMidriff

    Your SMTP summary is very good.  I'd only add that "undeliverable notices" MUST have a reply path of <> to prevent mail loops - such as, for example, if Initech's mail server says "sure, I'll deliver that" and then only later realizes that the mailbox doesn't exist or is full or whatnot.

  • janny boy (unregistered) in reply to Maurits
    Maurits:
    Your SMTP summary is very good.  I'd only add that "undeliverable notices" MUST have a reply path of <> to prevent mail loops - such as, for example, if Initech's mail server says "sure, I'll deliver that" and then only later realizes that the mailbox doesn't exist or is full or whatnot.


    It is indeed very good. RFC 821 has been superceded, however.

Leave a comment on “Wishin' There Was an Easier Way”

Log In or post as a guest

Replying to comment #:

« Return to Article