Subversion Repositories Kolibri OS

Rev

Rev 1301 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
481 diamond 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;
3
;    FTPS
4
;    FTP Server
5
;
6
;    Compile with FASM for Menuet
7
;
8
 
9
; note: telnet == 23, ftp cmd == 21, data on 20
10
 
11
use32
12
 
13
    org     0x0
14
 
15
    db      'MENUET01'              ; 8 byte id
16
    dd      1                       ; header version
17
    dd      START                   ; program start
18
    dd      I_END                   ; program image size
19
    dd      0x170000                ; required amount of memory
20
    dd      0x7FFF0                 ; esp = 0x7FFF0
21
    dd      0, 0                    ; no params, no path
22
 
661 ataualpa 23
include 'macros.inc'
481 diamond 24
; Various states of client connection
25
USER_NONE       equ 0   ; Awaiting a connection
26
USER_CONNECTED  equ 1   ; User just connected, prompt given
27
USER_USERNAME   equ 2   ; User given username
28
USER_LOGGED_IN  equ 3   ; User given password
29
 
30
 
31
 
32
 
33
 
34
START:                          ; start of execution
35
    ; Clear the screen memory
36
    mov     eax, '    '
37
    mov     edi,text
38
    mov     ecx,80*30 /4
39
    cld
40
    rep     stosd
41
 
42
    call    draw_window
43
 
44
    ; init the receive buffer pointer
45
    mov     [buffptr], buff
46
 
47
    ; Init FTP server state machine
48
    mov     [state], USER_NONE
49
 
50
    ; Open the listening socket
51
    call    connect
52
 
53
still:
54
    ; check connection status
55
    mov     eax,53
56
    mov     ebx,6               ; Get socket status
57
    mov     ecx,[CmdSocket]
485 heavyiron 58
    mcall
481 diamond 59
 
60
    mov     ebx, [CmdSocketStatus]
61
    mov     [CmdSocketStatus], eax
62
 
63
    cmp     eax, ebx
64
    je      waitev
65
 
66
    ; If the socket closed by remote host, open it again.
67
    cmp     eax, 7
68
    je      con
661 ataualpa 69
 
481 diamond 70
    ; If socket closed by Reset, open it again
71
    cmp     eax, 11
72
    je      con
73
 
74
    ; If a user has just connected, start by outputting welcome msg
75
    cmp     eax, 4
76
    jne     noc
77
 
78
    mov     esi, loginStr0
79
    mov     edx, loginStr0_end - loginStr0
80
    call    outputStr
81
 
82
    mov     [state], USER_CONNECTED
83
    jmp     noc
84
 
85
 
86
con:
87
    ; Need to call disconnect, since a remote close does not fully
88
    ; close the socket
89
    call    disconnect
1297 tsdima 90
    mov     eax,5
91
    mov     ebx,10          ; Delay for 100ms
92
    mcall
481 diamond 93
    call    connect
94
    jmp     noc
95
 
96
noc:
97
    ; Display the changed connected status
98
    call    draw_window
99
 
100
waitev:
101
    mov     eax,23                 ; wait here for event
102
    mov     ebx,1                 ; Delay for up to 1s
485 heavyiron 103
    mcall
481 diamond 104
 
105
    cmp     eax,1                  ; redraw request ?
106
    je      red
107
    cmp     eax,2                  ; key in buffer ?
108
    je      key
109
    cmp     eax,3                  ; button in buffer ?
110
    je      button
111
 
112
    ; any data from the socket?
113
 
114
    mov     eax, 53
115
    mov     ebx, 2                  ; Get # of bytes in input queue
116
    mov     ecx, [CmdSocket]
485 heavyiron 117
    mcall
481 diamond 118
    test    eax, eax
119
    jz      still
120
 
121
read_input:
122
    mov     eax, 53
123
    mov     ebx, 3                  ; Get a byte from socket in bl
124
    mov     ecx, [CmdSocket]
485 heavyiron 125
    mcall
481 diamond 126
 
127
    call    ftpRxCmdData            ; process incoming ftp command
128
 
129
    ; Keep processing data until there is no more to process
130
    mov     eax, 53
131
    mov     ebx, 2                  ; Get # of bytes in input queue
132
    mov     ecx, [CmdSocket]
485 heavyiron 133
    mcall
481 diamond 134
    cmp     eax, 0
135
    jne     read_input
136
 
137
    ; Now redraw the text text field.
138
    ; Probably not required, since ftp requires no
139
    ; console i/o.
140
    ; Leave in for now, for debugging.
141
; (fall through to "red:")
142
;    call    draw_text
143
;    jmp     still
144
 
145
red:                          ; REDRAW WINDOW
146
    call    draw_window
147
    jmp     still
148
 
149
key:                          ; KEY
150
    mov     eax,2                  ; get but ignore
485 heavyiron 151
    mcall
481 diamond 152
    jmp     still
153
 
154
button:
155
    mov     eax,17
485 heavyiron 156
    mcall
481 diamond 157
    cmp     ah,1
158
    jne     still
159
 
160
    ; Exit button pressed, so close socket and quit
161
    mov     eax,53
162
    mov     ebx,8
163
    mov     ecx,[CmdSocket]
485 heavyiron 164
    mcall
481 diamond 165
 
166
    ; ... terminate program
485 heavyiron 167
    or     eax,-1
168
    mcall
481 diamond 169
    jmp     still
170
 
171
 
172
 
173
;   *********************************************
174
;   *******  WINDOW DEFINITIONS AND DRAW ********
175
;   *********************************************
176
draw_window:
177
    pusha
178
 
179
    mov  eax,12
180
    mov  ebx,1
485 heavyiron 181
    mcall
481 diamond 182
 
183
    xor  eax,eax                   ; DRAW WINDOW
184
    mov  ebx,100*65536+491 + 8 +15
185
    mov  ecx,100*65536+270 + 20     ; 20 for status bar
661 ataualpa 186
    mov  edx,0x14000000
481 diamond 187
    mov  edi,labelt
485 heavyiron 188
    mcall
481 diamond 189
 
190
    ; draw status bar
191
    mov     eax, 13
192
    mov     ebx, 4*65536+484 + 8 +15
193
    mov     ecx, 270*65536 + 3
194
    mov     edx, 0x00557799
485 heavyiron 195
    mcall
481 diamond 196
 
197
 
198
    mov  esi,contlen-contt          ; display connected status
199
    mov     edx, contt
200
    cmp     [CmdSocketStatus], 4    ; 4 is connected
201
    je      pcon
202
    mov     esi,discontlen-discontt
203
    mov     edx, discontt
204
pcon:
205
 
206
    mov  eax,4                      ; status text
207
    mov  ebx,380*65536+276
208
    mov  ecx,0x00ffffff
485 heavyiron 209
    mcall
481 diamond 210
 
211
    ; Draw the text on the screen, clearing it first
212
    ; This can go when we loose debuggin info.
213
    xor  eax,eax
214
    mov  edi,text+80*30
215
    mov  ecx,80*30 /4
216
    cld
217
    rep  stosd
218
 
219
    call draw_text
220
 
221
    mov  eax,12
222
    mov  ebx,2
485 heavyiron 223
    mcall
481 diamond 224
 
225
    popa
226
 
227
    ret
228
 
229
 
230
;***************************************************************************
231
;   Function
232
;      draw_text
233
;
234
;   Description
235
;       Updates the text on the screen. This is part of the debugging code
236
;
237
;   Inputs
238
;       Character to add in bl
239
;
240
;***************************************************************************
241
draw_text:
242
 
243
    pusha
244
 
245
    mov  esi,text
246
    mov  eax,0
247
    mov  ebx,0
248
  newletter:
249
    mov  cl,[esi]
250
    cmp  cl,[esi+30*80]
251
    jz   noletter
252
  yesletter:
253
    mov  [esi+30*80],cl
254
 
255
    ; erase character
256
 
257
    pusha
258
    mov     edx, 0                  ; bg colour
259
    mov     ecx, ebx
260
    add     ecx, 26
261
    shl     ecx, 16
262
    mov     cx, 9
263
    mov     ebx, eax
264
    add     ebx, 6
265
    shl     ebx, 16
266
    mov     bx, 6
267
    mov     eax, 13
485 heavyiron 268
    mcall
481 diamond 269
    popa
270
 
271
    ; draw character
272
 
273
    pusha
274
    mov     ecx, 0x00ffffff
275
    push bx
276
    mov  ebx,eax
277
    add  ebx,6
278
    shl  ebx,16
279
    pop  bx
280
    add  bx,26
281
    mov  eax,4
282
    mov  edx,esi
283
    mov  esi,1
485 heavyiron 284
    mcall
481 diamond 285
    popa
286
 
287
  noletter:
288
 
289
    add  esi,1
290
    add  eax,6
291
    cmp  eax,80*6
292
    jb   newletter
293
    mov  eax,0
294
    add  ebx,10
295
    cmp  ebx,24*10
296
    jb   newletter
297
 
298
    popa
299
    ret
300
 
301
 
302
 
303
;***************************************************************************
304
;   Function
305
;      ftpRxCmdData
306
;
307
;   Description
308
;       Prcoesses incoming command data, calling a handler for each command.
309
;       Commands are built up in buff before being processed.
310
;
311
;   Inputs
312
;       Character to add in bl
313
;
314
;***************************************************************************
315
ftpRxCmdData:
316
    ; Quit if we are not connected
317
    ;( This case shouldn't be necessary, but be safe )
318
    mov     al, [state]
319
    cmp     al, USER_NONE
320
    je      frcd_exit
321
 
322
    ; Store the incoming character
323
    mov     esi, [buffptr]
324
    mov     [esi], bl
325
    inc     esi
326
    mov     [buffptr], esi
327
 
328
    ; For debugging, show the data coming in
329
    pusha
330
    call    printChar
331
    popa
332
 
333
    ; Do we have an end of line? (LF)
334
    ; if not, just exit
335
    cmp     bl, 0x0a
336
    jne     frcd_exit
337
 
338
    ; OK we have a complete command.
339
    ; Process, and send response
340
 
341
    ; There are a number of states involved in ftp,
342
    ; to do with logging in.
343
 
344
    mov     al, [state]
345
    cmp     al, USER_CONNECTED
346
    jne     fs001
347
 
348
    ; This should be the username
349
 
350
    ; TODO validate username
351
 
352
    ; OK, username accepted - ask for password
353
    mov     esi, loginStr1
354
    mov     edx, loginStr1_end - loginStr1
355
    call    outputStr
356
 
357
    mov     [state], USER_USERNAME
358
 
359
    ; init the receive buffer pointer
360
    mov     [buffptr], buff
361
 
362
    jmp     frcd_exit
363
 
364
fs001:
365
    cmp     al, USER_USERNAME
366
    jne     fs002
367
 
368
    ; This should be the password
369
 
370
    ; TODO validate password
371
 
372
    ; OK, password accepted - show they are logged in
373
    mov     esi, loginStr2
374
    mov     edx, loginStr2_end - loginStr2
375
    call    outputStr
376
 
377
    mov     [state], USER_LOGGED_IN
378
 
379
    ; init the receive buffer pointer
380
    mov     [buffptr], buff
381
 
382
    jmp     frcd_exit
383
 
384
fs002:
385
    cmp     al, USER_LOGGED_IN
386
    jne     fs003
387
 
388
    ; This should be a cmd
389
    call    findCmd
390
    mov     eax, [cmdPtr]
391
    cmp     eax, 0
392
 
393
    je      fs002b
394
 
395
    call    [cmdPtr]
396
 
397
fs002a:
398
    ; init the receive buffer pointer
399
    mov     [buffptr], buff
400
 
401
    jmp     frcd_exit
402
 
403
fs002b:
404
    ; an unsupported command was entered.
405
    ; Tell user that the command is not supported
406
 
407
    mov     esi, unsupStr
408
    mov     edx, unsupStr_end - unsupStr
409
    call    outputStr
410
 
411
    jmp     fs002a
412
 
413
fs003:
414
frcd_exit:
415
    ret
416
 
417
 
418
 
419
;***************************************************************************
420
;   Function
421
;      outputStr
422
;
423
;   Description
424
;       Sends a string over the 'Command' socket
425
;
426
;   Inputs
427
;       String in esi
428
;       Length in edx
429
;
430
;***************************************************************************
431
outputStr:
432
    push    esi
433
    push    edx
434
    mov     eax,53
435
    mov     ebx,7
436
    mov     ecx,[CmdSocket]
485 heavyiron 437
    mcall
481 diamond 438
    pop     edx
439
    pop     esi
661 ataualpa 440
 
481 diamond 441
    cmp     eax, 0
442
    je      os_exit
661 ataualpa 443
 
444
    ; The TCP/IP transmit queue is full; Wait a bit, then retry
481 diamond 445
    pusha
446
    mov     eax,5
1301 tsdima 447
    mov     ebx,1                 ; Delay for up 10ms
485 heavyiron 448
    mcall
481 diamond 449
    popa
661 ataualpa 450
    jmp     outputStr
481 diamond 451
os_exit:
452
    ret
453
 
454
 
455
 
456
;***************************************************************************
457
;   Function
458
;      outputDataStr
459
;
460
;   Description
461
;       Sends a string over the 'Data' socket
462
;
463
;   Inputs
464
;       String in esi
465
;       Length in edx
466
;
467
;***************************************************************************
468
outputDataStr:
469
    push    esi
470
    push    edx
471
    mov     eax,53
472
    mov     ebx,7
473
    mov     ecx,[DataSocket]
485 heavyiron 474
    mcall
481 diamond 475
    pop     edx
476
    pop     esi
477
 
478
    cmp     eax, 0
479
    je      ods_exit
480
 
661 ataualpa 481
    ; The TCP/IP transmit queue is full; Wait a bit, then retry
481 diamond 482
    pusha
483
    mov     eax,5
1301 tsdima 484
    mov     ebx,1                 ; Delay for up 10ms
485 heavyiron 485
    mcall
481 diamond 486
    popa
661 ataualpa 487
    jmp     outputDataStr
481 diamond 488
ods_exit:
489
    ret
490
 
491
 
492
 
493
;***************************************************************************
494
;   Function
495
;      printChar
496
;
497
;   Description
498
;       Writes a character to the screen; Used to display the data coming
499
;       in from the user. Really only useful for debugging.
500
;
501
;   Inputs
502
;       Character in bl
503
;
504
;***************************************************************************
505
printChar:
506
    cmp     bl,13                          ; BEGINNING OF LINE
507
    jne     nobol
508
    mov     ecx,[pos]
509
    add     ecx,1
510
boll1:
511
    sub     ecx,1
512
    mov     eax,ecx
513
    xor     edx,edx
514
    mov     ebx,80
515
    div     ebx
516
    cmp     edx,0
517
    jne     boll1
518
    mov     [pos],ecx
519
    jmp     newdata
520
nobol:
521
 
522
    cmp     bl,10                            ; LINE DOWN
523
    jne     nolf
524
addx1:
525
    add     [pos],dword 1
526
    mov     eax,[pos]
527
    xor     edx,edx
528
    mov     ecx,80
529
    div     ecx
530
    cmp     edx,0
531
    jnz     addx1
532
    mov     eax,[pos]
533
    jmp     cm1
534
nolf:
535
 
536
    cmp     bl,8                            ; BACKSPACE
537
    jne     nobasp
538
    mov     eax,[pos]
539
    dec     eax
540
    mov     [pos],eax
541
    mov     [eax+text],byte 32
542
    mov     [eax+text+60*80],byte 0
543
    jmp     newdata
544
nobasp:
545
 
546
    cmp     bl,15                           ; CHARACTER
547
    jbe     newdata
548
putcha:
549
    mov     eax,[pos]
550
    mov     [eax+text],bl
551
    mov     eax,[pos]
552
    add     eax,1
553
cm1:
554
    mov     ebx,[scroll+4]
555
    imul    ebx,80
556
    cmp     eax,ebx
557
    jb      noeaxz
558
    mov     esi,text+80
559
    mov     edi,text
560
    mov     ecx,ebx
561
    cld
562
    rep     movsb
563
    mov     eax,ebx
564
    sub     eax,80
565
noeaxz:
566
    mov     [pos],eax
567
newdata:
568
    ret
569
 
570
 
571
;***************************************************************************
572
;   Function
573
;      disconnect
574
;
575
;   Description
576
;       Closes the command socket
577
;
578
;   Inputs
579
;       None
580
;
581
;***************************************************************************
582
disconnect:
583
    mov     eax, 53         ; Stack Interface
584
    mov     ebx,8           ; Close TCP socket
585
    mov     ecx,[CmdSocket]
485 heavyiron 586
    mcall
481 diamond 587
    ret
588
 
589
 
661 ataualpa 590
 
481 diamond 591
;***************************************************************************
592
;   Function
593
;      disconnectData
594
;
595
;   Description
596
;       Closes the data socket
597
;
598
;   Inputs
599
;       None
600
;
601
;***************************************************************************
602
disconnectData:
603
    ; This delay would be better done by allowing the socket code
604
    ; to wait for all data to pass through the stack before closing
605
    pusha
606
    mov     eax,5
1287 tsdima 607
    mov     ebx,10          ; Delay for 100ms
485 heavyiron 608
    mcall
481 diamond 609
    popa
610
 
611
    mov     eax, 53         ; Stack Interface
612
    mov     ebx,8           ; Close TCP socket
613
    mov     ecx,[DataSocket]
485 heavyiron 614
    mcall
481 diamond 615
    ret
616
 
617
 
618
 
619
 
620
;***************************************************************************
621
;   Function
622
;      connect
623
;
624
;   Description
625
;       Opens the command socket
626
;
627
;   Inputs
628
;       None
629
;
630
;***************************************************************************
631
connect:
632
    pusha
633
 
634
    mov     eax, 53     ; Stack Interface
635
    mov     ebx, 5      ; Open TCP socket
636
    mov     esi, 0      ; No remote IP address
637
    mov     edx, 0      ; No remote port
638
    mov     ecx, 21     ; ftp command port id
639
    mov     edi, 0      ; passive open
485 heavyiron 640
    mcall
481 diamond 641
    mov     [CmdSocket], eax
642
 
643
    popa
644
 
645
    ret
646
 
647
 
648
 
649
;***************************************************************************
650
;   Function
651
;      connectData
652
;
653
;   Description
654
;       Opens the data socket
655
;
656
;   Inputs
657
;       None
658
;
659
;***************************************************************************
660
connectData:
661
    pusha
662
 
663
    mov     eax, 53     ; Stack Interface
664
    mov     ebx, 5      ; Open TCP socket
665
    mov     esi, [DataIP]      ; remote IP address
666
    mov     edx, [DataPort]    ; remote port
1287 tsdima 667
    mov     ecx, 0      ; ftp data port id
481 diamond 668
    mov     edi, 1      ; active open
485 heavyiron 669
    mcall
481 diamond 670
    mov     [DataSocket], eax
671
 
672
    popa
673
 
674
    ret
675
 
676
 
677
 
678
 
679
;***************************************************************************
680
;   Function
681
;      findCmd
682
;
683
;   Description
684
;       Scans the command string for a valid command. The command string
685
;       is in the global variable buff.
686
;
687
;       Returns result in cmdPtr. This will be zero if none found
688
;
689
;   Inputs
690
;       None
691
;
692
;***************************************************************************
693
findCmd:
694
    ; Setup to return 'none' in cmdPtr, if we find no cmd
695
    mov     eax, 0
696
    mov     [cmdPtr], eax
697
    cld
698
    mov     esi, buff
699
    mov     edi, CMDList
700
 
701
fc000:
702
    cmp     [edi], byte 0   ; Are we at the end of the CMDList?
703
    je      fc_exit
704
 
705
fc000a:
706
    cmpsb
707
 
708
    je      fc_nextbyte
709
 
710
    ; Command is different - move to the next entry in cmd table
711
    mov     esi, buff
712
 
713
fc001:
714
    ; skip to the next command in the list
715
    cmp     [edi], byte 0
716
    je      fc002
717
    inc     edi
718
    jmp     fc001
719
fc002:
720
    add     edi, 5
721
    jmp     fc000
722
 
723
fc_nextbyte:
724
    ; Have we reached the end of the CMD text?
725
    cmp     [edi], byte 0
726
    je      fc_got      ; Yes - so we have a match
727
    jmp     fc000a      ; No - loop back
728
 
729
fc_got:
730
    ; Copy the function pointer for the selected command
731
    inc     edi
732
    mov     eax, [edi]
733
    mov     [cmdPtr], eax
734
 
735
fc_exit:
736
    ret
737
 
738
 
739
 
740
;***************************************************************************
741
;   Function
742
;      decStr2Byte
743
;
744
;   Description
745
;       Converts the decimal string pointed to by esi to a byte
746
;
747
;   Inputs
748
;       string ptr in esi
749
;
750
;   Outputs
751
;       esi points to next character not in string
752
;       eax holds result ( 0..255)
753
;
754
;***************************************************************************
755
decStr2Byte:
756
    xor     eax, eax
757
    xor     ebx, ebx
758
    mov     ecx, 3
759
 
760
dsb001:
761
    mov     bl, [esi]
762
 
763
    cmp     bl, '0'
764
    jb      dsb_exit
765
    cmp     bl, '9'
766
    ja      dsb_exit
767
 
768
    imul    eax, 10
769
    add     eax, ebx
770
    sub     eax, '0'
771
    inc     esi
772
    loop    dsb001
773
 
774
dsb_exit:
775
    ret
776
 
777
 
778
 
779
;***************************************************************************
780
;   Function
781
;      parsePortStr
782
;
783
;   Description
784
;       Converts the parameters of the PORT command, and stores them in the
785
;       appropriate variables.
786
;
787
;   Inputs
788
;       None ( string in global variable buff )
789
;
790
;   Outputs
791
;       None
792
;
793
;***************************************************************************
794
parsePortStr:
795
    ; skip past the PORT text to get the the parameters. The command format
796
    ; is
797
    ; PORT i,i,i,i,p,p,0x0d,0x0a
798
    ; where i and p are decimal byte values, high byte first.
799
    xor     eax, eax
800
    mov     [DataIP], eax
801
    mov     [DataPort], eax
802
    mov     esi, buff + 4       ; Start at first space character
803
 
804
pps001:
805
    cmp     [esi], byte ' '     ; Look for first non space character
806
    jne     pps002
807
    inc     esi
808
    jmp     pps001
809
 
810
pps002:
811
    call    decStr2Byte
812
    add     [DataIP], eax
813
    ror     dword [DataIP], 8
814
    inc     esi
815
    call    decStr2Byte
816
    add     [DataIP], eax
817
    ror     dword [DataIP], 8
818
    inc     esi
819
    call    decStr2Byte
820
    add     [DataIP], eax
821
    ror     dword [DataIP], 8
822
    inc     esi
823
    call    decStr2Byte
824
    add     [DataIP], eax
825
    ror     dword [DataIP], 8
826
    inc     esi
827
    call    decStr2Byte
828
    add     [DataPort], eax
829
    shl     [DataPort], 8
830
    inc     esi
831
    call    decStr2Byte
832
    add     [DataPort], eax
833
 
834
    ret
835
 
836
 
837
 
838
;***************************************************************************
839
;   Function
840
;      sendDir
841
;
842
;   Description
843
;       Transmits the directory listing over the data connection.
844
;       The data connection is already open.
845
;
846
;   Inputs
661 ataualpa 847
;       None
481 diamond 848
;
849
;   Outputs
850
;       None
851
;
852
;***************************************************************************
853
sendDir:
854
        mov     ebx, dirinfoblock
855
        and     dword [ebx+4], 0        ; start from zero block
856
sd001:
857
; Read the next DirBlocksPerCall (=16) blocks
858
        mov     eax, 70
485 heavyiron 859
        mcall
481 diamond 860
; Did we read anything?
861
        test    eax, eax
862
        jz      @f
863
        cmp     eax, 6
864
        jnz     sd_exit
865
@@:
866
        test    ebx, ebx
867
        jz      sd_exit
868
; Parse these blocks. There could be up to 16 files specified
869
        mov     esi, text + 0x1300 + 0x20
870
sd002:
871
        dec     ebx
872
        js      sd004
873
        push    ebx
874
; OK, lets parse the entry. Ignore volume entries
875
        test    byte [esi], 8
876
        jnz     sd003
877
; Valid file or directory. Start to compose the string we will send
878
        mov     edi, dirStr
879
; If we have been called as a result of an NLST command, we only display
880
; the filename
881
        cmp     [buff], byte 'N'
882
        jz      sd006
883
 
884
        mov     [edi], byte '-'
885
        test    byte [esi], 10h
886
        jz      @f
887
        mov     [edi], byte 'd'
888
@@:
889
; Ok, now copy across the directory listing text that will be constant
890
; ( I dont bother looking at the read only or archive bits )
891
 
892
        mov     ebx, tmplStr
893
@@:
894
        inc     edi
895
        mov     al, [ebx]
896
        test    al, al
897
        jz      @f
898
        mov     [edi], al
899
        inc     ebx
900
        jmp     @b
901
@@:
902
; point to the last character of the string;
903
; We will write the file size here, backwards
904
        push    edi             ; Remember where the string ends
905
 
906
        dec     edi
907
; eax holds the number
908
        mov     eax, [esi+32]
909
        mov     ebx, 10
910
@@:
911
        xor     edx, edx
912
        div     ebx
913
        add     dl, '0'
914
        mov     [edi], dl
915
        dec     edi
916
        test    eax, eax
917
        jnz     @b
918
 
919
        pop     edi
920
; now create the time & date fields
921
;timeStr:            db ' Jan 1    2000 ',0
922
        mov     al, ' '
923
        stosb
924
        movzx   eax, byte [esi+28+1]
925
        mov     eax, dword [months + (eax-1)*4]
926
        stosd
927
        mov     al, byte [esi+28]
928
        aam
929
        test    ah, ah
930
        jz      sd005a
931
        xchg    al, ah
932
        add     ax, '00'
933
        jmp     sd005b
934
sd005a:
935
        add     al, '0'
936
        mov     ah, ' '
937
sd005b:
938
        stosw
939
        mov     al, ' '
940
        mov     ecx, 6
941
        rep     stosb
942
        push    edi
943
        movzx   eax, word [esi+28+2]
944
@@:
945
        xor     edx, edx
946
        div     ebx
947
        add     dl, '0'
948
        mov     [edi], dl
949
        dec     edi
950
        test    eax, eax
951
        jnz     @b
952
        pop     edi
953
        inc     edi
954
        mov     al, ' '
955
        stosb
956
sd006:
957
; ** End of copying
958
 
959
; now copy the filename across
960
        lea     ebx, [esi+40]
961
@@:
962
        mov     al, [ebx]
963
        inc     ebx
964
        test    al, al
965
        jz      @f
966
        stosb
967
        jmp     @b
968
@@:
969
terminate:
970
; Now terminate the line by putting CRLF sequence in
971
        mov     al, 0x0D
972
        stosb
973
        mov     al, 0x0A
974
        stosb
975
; Send the completed line to the user over data socket
976
        push    esi
977
        mov     esi, dirStr
978
        mov     edx, edi
979
        sub     edx, esi
980
        call    outputDataStr
981
        pop     esi
982
 
983
sd003:                  ; Move to next entry in the block
984
        pop     ebx
985
        add     esi, 304
986
        jmp     sd002
987
sd004:
988
        mov     ebx, dirinfoblock
989
        add     dword [ebx+4], DirBlocksPerCall
990
        jmp     sd001
991
 
992
sd_exit:
993
        ret
994
 
995
 
996
 
997
 
998
 
999
;***************************************************************************
1000
;   Function
1001
;      setupFilePath
1002
;
1003
;   Description
1004
;       Copies the file name from the input request string into the
1005
;       file descriptor
1006
;
1007
;   Inputs
661 ataualpa 1008
;       None
481 diamond 1009
;
1010
;   Outputs
1011
;       None
1012
;
1013
;***************************************************************************
1014
setupFilePath:
1015
    mov     esi, buff + 4       ; Point to (1 before) first character of file
661 ataualpa 1016
 
481 diamond 1017
    ; Skip any trailing spaces or / character
661 ataualpa 1018
sfp001:
481 diamond 1019
    inc     esi
1020
    cmp     [esi], byte ' '
1021
    je      sfp001
1022
    cmp     [esi], byte '/'
1023
    je      sfp001
661 ataualpa 1024
 
481 diamond 1025
    ; esi points to start of filename.
661 ataualpa 1026
 
1027
 
481 diamond 1028
    ; Copy across the directory path '/'
1029
    ; into the fileinfoblock
1030
    mov     edi, filename
1031
    mov     dword [edi], '/RD/'
1032
    mov     word [edi+4], '1/'
1033
    add     edi, 6
661 ataualpa 1034
 
481 diamond 1035
    ; Copy across the filename
1036
sfp002:
1037
    cld
1038
    movsb
1039
    cmp     [esi], byte 0x0d
1040
    jne     sfp002
661 ataualpa 1041
    mov     [edi], byte 0
481 diamond 1042
    ret
1043
 
1044
 
1045
 
1046
 
1047
;***************************************************************************
1048
;   Function
1049
;      sendFile
1050
;
1051
;   Description
1052
;       Transmits the requested file over the open data socket
1053
;       The file to send is named in the buff string
1054
;
1055
;   Inputs
661 ataualpa 1056
;       None
481 diamond 1057
;
1058
;   Outputs
1059
;       None
1060
;
1061
;***************************************************************************
1062
sendFile:
1063
    call    setupFilePath
1064
 
1065
    ; init fileblock descriptor, for file read
1066
    mov     ebx, fileinfoblock
1067
    and     dword [ebx], 0 ; read cmd
1068
    and     dword [ebx+4], 0 ; first block
1301 tsdima 1069
    mov     dword [ebx+12], 0x400 ; block size
481 diamond 1070
 
1071
sf002a:
661 ataualpa 1072
    ; now read the file..
481 diamond 1073
    mov     eax,70
485 heavyiron 1074
    mcall
481 diamond 1075
    test    eax, eax
1076
    jz      @f
1077
    cmp     eax, 6
1078
    jnz     sf_exit
1079
@@:
1080
    push    eax
1081
    mov     esi, text + 0x1300
1082
    mov     edx, ebx
1083
    call    outputDataStr
1084
    pop     eax
1085
    test    eax, eax
1086
    jnz     sf_exit
1087
; wait a bit
1088
    mov     eax, 5
1301 tsdima 1089
    mov     ebx, 1
485 heavyiron 1090
    mcall
481 diamond 1091
    mov     ebx, fileinfoblock
1092
    add     dword [ebx+4], edx
1093
    jmp     sf002a
1094
 
661 ataualpa 1095
sf_exit:
481 diamond 1096
    ret
1097
 
661 ataualpa 1098
 
481 diamond 1099
;***************************************************************************
1100
;   Function
1101
;      getFile
1102
;
1103
;   Description
1104
;       Receives the specified file over the open data socket
1105
;       The file to receive is named in the buff string
1106
;
1107
;   Inputs
661 ataualpa 1108
;       None
481 diamond 1109
;
1110
;   Outputs
1111
;       None
1112
;
1113
;***************************************************************************
1114
getFile:
1115
    call    setupFilePath
661 ataualpa 1116
 
481 diamond 1117
    ; init fileblock descriptor, for file write
1118
    xor     eax, eax
1119
    mov     [fsize], eax            ; Start filelength at 0
1120
    mov     [fileinfoblock+4], eax    ; set to 0
1121
    inc     eax
1122
    inc     eax
1123
    mov     [fileinfoblock], eax    ; write cmd
661 ataualpa 1124
 
481 diamond 1125
    ; Read data from the socket until the socket closes
1126
    ; loop
1127
    ;   loop
1128
    ;     read byte from socket
1129
    ;     write byte to file buffer
1130
    ;   until no more bytes in socket
1131
    ;   sleep 100ms
1132
    ; until socket no longer connected
1133
    ; write file to ram
661 ataualpa 1134
 
481 diamond 1135
gf000:
1136
    mov     eax, 53
1137
    mov     ebx, 2                  ; Get # of bytes in input queue
1138
    mov     ecx, [DataSocket]
485 heavyiron 1139
    mcall
481 diamond 1140
    test    eax, eax
1141
    je      gf_sleep
661 ataualpa 1142
 
481 diamond 1143
    mov     eax, 53
1301 tsdima 1144
    mov     ebx, 11                 ; Get a bytes from socket
481 diamond 1145
    mov     ecx, [DataSocket]
1301 tsdima 1146
    mov     edx, text + 0x1300
1147
    add     edx, dword [fsize]
1148
    mcall                           ; returned data len in eax
1149
    add     dword [fsize], eax
661 ataualpa 1150
 
481 diamond 1151
    jmp     gf000
1152
 
1153
gf_sleep:
1154
    ; Check to see if socket closed...
1155
    mov     eax,53
1156
    mov     ebx,6               ; Get socket status
1157
    mov     ecx,[DataSocket]
485 heavyiron 1158
    mcall
481 diamond 1159
 
1160
    cmp     eax, 7
1161
    jne     gf001               ; still open, so just sleep a bit
1162
 
1163
    ; Finished, so write the file
1164
    mov     eax, [fsize]
1165
    mov     [fileinfoblock+12], eax
1166
    mov     eax,70
1167
    mov     ebx,fileinfoblock
485 heavyiron 1168
    mcall
481 diamond 1169
 
1170
    ret                         ; Finished
1171
 
1172
gf001:
1173
    ; wait a bit
1174
    mov     eax,5
1301 tsdima 1175
    mov     ebx,1               ; Delay for up 10ms
485 heavyiron 1176
    mcall
481 diamond 1177
    jmp     gf000               ; try for more data
1178
 
1179
 
1180
 
661 ataualpa 1181
 
1182
 
481 diamond 1183
;***************************************************************************
1184
;   COMMAND HANDLERS FOLLOW
1185
;
1186
;   These handlers implement the functionality of each supported FTP Command
1187
;
1188
;***************************************************************************
1189
 
1190
cmdPWD:
1191
    ; OK, show the directory name text
1192
    mov     esi, ramdir
1193
    mov     edx, ramdir_end - ramdir
1194
    call    outputStr
1195
 
1196
    ; TODO give real directory
1197
 
1198
    ret
1199
 
1200
 
1201
cmdCWD:
1202
    ; Only / is valid for the ramdisk
1203
    cmp     [buff+5], byte 0x0d
1204
    jne     ccwd_000
661 ataualpa 1205
 
481 diamond 1206
    ; OK, show the directory name text
1207
    mov     esi, chdir
1208
    mov     edx, chdir_end - chdir
1209
    jmp     ccwd_001
661 ataualpa 1210
 
481 diamond 1211
ccwd_000:
1212
    ; Tell user there is no such directory
1213
    mov     esi, noFileStr
1214
    mov     edx, noFileStr_end - noFileStr
1215
 
1216
ccwd_001:
1217
    call    outputStr
1218
 
1219
    ret
1220
 
1221
 
1222
cmdQUIT:
1223
    ; The remote end will do the close; We just
1224
    ; say goodbye.
1225
    mov     esi, byeStr
1226
    mov     edx, byeStr_end - byeStr
1227
    call    outputStr
1228
    ret
1229
 
1230
 
1231
cmdABOR:
1232
 
1233
    ; Close port
1234
    call    disconnectData
1235
 
1236
    mov     esi, abortStr
1237
    mov     edx, abortStr_end - abortStr
1238
    call    outputStr
1239
 
1240
    ret
1241
 
1242
cmdPORT:
1243
    ; TODO
1244
    ; Copy the IP and port values to DataIP and DataPort
1245
 
1246
    call    parsePortStr
1247
 
1248
    ; Indicate the command was accepted
1249
    mov     esi, cmdOKStr
1250
    mov     edx, cmdOKStr_end - cmdOKStr
1251
    call    outputStr
1252
    ret
1253
 
1254
cmdnoop:
1255
    ; Indicate the command was accepted
1256
    mov     esi, cmdOKStr
1257
    mov     edx, cmdOKStr_end - cmdOKStr
1258
    call    outputStr
1259
    ret
1260
 
1261
 
1262
cmdTYPE:
1263
    ; TODO
1264
    ; Note the type field selected - reject if needed.
1265
 
1266
    ; Indicate the command was accepted
1267
    mov     esi, cmdOKStr
1268
    mov     edx, cmdOKStr_end - cmdOKStr
1269
    call    outputStr
1270
    ret
1271
 
1272
cmdsyst:
1273
    ; Indicate the system type
1274
    mov     esi, systStr
1275
    mov     edx, systStr_end - systStr
1276
    call    outputStr
1277
    ret
1278
 
1279
 
1280
cmdDELE:
1281
    call    setupFilePath
1282
 
1283
    mov     ebx, fileinfoblock
1284
    mov     dword [ebx], 8
1285
    and     dword [ebx+4], 0
1286
    push    dword [ebx+12]
1287
    push    dword [ebx+16]
1288
    and     dword [ebx+12], 0
1289
    and     dword [ebx+16], 0
1290
    mov     eax, 70
485 heavyiron 1291
    mcall
1302 tsdima 1292
    mov     ebx, fileinfoblock
481 diamond 1293
    pop     dword [ebx+16]
1294
    pop     dword [ebx+12]
661 ataualpa 1295
 
481 diamond 1296
    test    eax, eax
1297
    jne     cmdDele_err
1298
 
1299
    mov     esi, delokStr
1300
    mov     edx, delokStr_end - delokStr
1301
    call    outputStr
661 ataualpa 1302
 
481 diamond 1303
    jmp     cmdDele_exit
661 ataualpa 1304
 
1305
cmdDele_err:
481 diamond 1306
    mov     esi, noFileStr
1307
    mov     edx, noFileStr_end - noFileStr
1308
    call    outputStr
661 ataualpa 1309
 
1310
 
481 diamond 1311
cmdDele_exit:
1312
    ret
1313
 
1314
 
1315
cmdNLST:
1316
cmdLIST:
1317
    ; Indicate the command was accepted
1318
    mov     esi, startStr
1319
    mov     edx, startStr_end - startStr
1320
    call    outputStr
1321
 
1322
    call    connectData
1323
 
1324
    ; Wait for socket to establish
1325
 
1326
cl001:
1327
    ; wait a bit
1328
    mov     eax,5
1329
    mov     ebx,10                ; Delay for up 100ms
485 heavyiron 1330
    mcall
481 diamond 1331
 
1332
    ; check connection status
1333
    mov     eax,53
1334
    mov     ebx,6               ; Get socket status
1335
    mov     ecx,[DataSocket]
485 heavyiron 1336
    mcall
481 diamond 1337
 
1338
    cmp     eax, 4
1339
    jne     cl001
1340
 
1341
    ; send directory listing
1342
    call    sendDir
661 ataualpa 1343
 
481 diamond 1344
    ; Close port
1345
    call    disconnectData
1346
 
1347
    mov     esi, endStr
1348
    mov     edx, endStr_end - endStr
1349
    call    outputStr
1350
    ret
1351
 
1352
cmdRETR:
1353
    ; Indicate the command was accepted
1354
    mov     esi, startStr
1355
    mov     edx, startStr_end - startStr
1356
    call    outputStr
1357
 
1358
    call    connectData
1359
 
1360
    ; Wait for socket to establish
1361
 
1362
cr001:
1363
    ; wait a bit
1364
    mov     eax,5
1365
    mov     ebx,10                ; Delay for up 100ms
485 heavyiron 1366
    mcall
481 diamond 1367
 
1368
    ; check connection status
1369
    mov     eax,53
1370
    mov     ebx,6               ; Get socket status
1371
    mov     ecx,[DataSocket]
485 heavyiron 1372
    mcall
481 diamond 1373
 
1374
    cmp     eax, 4
1375
    jne     cr001
1376
 
1377
    ; send data to remote user
1378
    call    sendFile
661 ataualpa 1379
 
481 diamond 1380
    ; Close port
1381
    call    disconnectData
1382
 
1383
    mov     esi, endStr
1384
    mov     edx, endStr_end - endStr
1385
    call    outputStr
1386
 
1387
 
1388
    ret
1389
 
1390
 
1391
cmdSTOR:
1392
    ; Indicate the command was accepted
1393
    mov     esi, storStr
1394
    mov     edx, storStr_end - storStr
1395
    call    outputStr
1396
 
1397
    call    connectData
1398
 
1399
    ; Wait for socket to establish
1400
 
1401
cs001:
1402
    ; wait a bit
1403
    mov     eax,5
1404
    mov     ebx,10                ; Delay for up 100ms
485 heavyiron 1405
    mcall
481 diamond 1406
 
1407
    ; check connection status
1408
    mov     eax,53
1409
    mov     ebx,6               ; Get socket status
1410
    mov     ecx,[DataSocket]
485 heavyiron 1411
    mcall
481 diamond 1412
 
1413
    cmp     eax, 4
1414
    je      @f
1415
    cmp     eax, 7
1416
    jne     cs001
1417
@@:
1418
 
1419
    ; get data file from remote user
1420
    call    getFile
661 ataualpa 1421
 
481 diamond 1422
    mov     esi, endStr
1423
    mov     edx, endStr_end - endStr
1424
    call    outputStr
1425
 
1426
    ; Close port
1427
    call    disconnectData
1428
 
1429
    ret
1430
 
1431
 
1432
 
1433
; DATA AREA
1434
 
1435
; This is the list of supported commands, and the function to call
1436
; The list end with a NULL.
1437
CMDList:
1438
                    db  'pwd',0
1439
                    dd  cmdPWD
1440
 
1441
                    db  'PWD',0
1442
                    dd  cmdPWD
1443
 
1444
                    db  'XPWD',0
1445
                    dd  cmdPWD
1446
 
1447
                    db  'xpwd',0
1448
                    dd  cmdPWD
1449
 
1450
                    db  'QUIT',0
1451
                    dd  cmdQUIT
1452
 
1453
                    db  'quit',0
1454
                    dd  cmdQUIT
1455
 
1456
                    db  'PORT',0
1457
                    dd  cmdPORT
1458
 
1459
                    db  'port',0
1460
                    dd  cmdPORT
1461
 
1462
                    db  'LIST',0
1463
                    dd  cmdLIST
1464
 
1465
                    db  'list',0
1466
                    dd  cmdLIST
1467
 
1468
                    db  'NLST',0
1469
                    dd  cmdNLST
1470
 
1471
                    db  'nlst',0
1472
                    dd  cmdNLST
1473
 
1474
                    db  'TYPE',0
1475
                    dd  cmdTYPE
1476
 
1477
                    db  'type',0
1478
                    dd  cmdTYPE
1479
 
1480
                    db  'syst',0
1481
                    dd  cmdsyst
1482
 
1483
                    db  'noop',0
1484
                    dd  cmdnoop
1485
 
1486
                    db  'CWD',0
1487
                    dd  cmdCWD
1488
 
1489
                    db  'cwd',0
1490
                    dd  cmdCWD
1491
 
1492
                    db  'RETR',0
1493
                    dd  cmdRETR
1494
 
1495
                    db  'retr',0
1496
                    dd  cmdRETR
1497
 
1498
                    db  'DELE',0
1499
                    dd  cmdDELE
1500
 
1501
                    db  'dele',0
1502
                    dd  cmdDELE
1503
 
1504
                    db  'stor',0
1505
                    dd  cmdSTOR
1506
 
1507
                    db  'STOR',0
1508
                    dd  cmdSTOR
1509
 
1510
                    db  'ABOR',0
1511
                    dd  cmdABOR
1512
 
1513
                    db  'abor',0
1514
                    dd  cmdABOR
1515
 
1516
                    db  0xff,0xf4,0xff,0xf2,'ABOR',0
1517
                    dd  cmdABOR
1518
 
1519
                    db  0
1520
 
1521
 
1522
cmdPtr              dd  0
1523
CmdSocket           dd  0x0
1524
CmdSocketStatus     dd  0x0
1525
DataSocket          dd  0x0
1526
DataSocketStatus    dd  0x0
1527
DataPort            dd  0x00
1528
DataIP              dd  0x00
1529
pos                 dd  80 * 1
1530
scroll              dd  1
1531
                    dd  24
1532
 
1533
labelt              db  'FTP Server v0.1',0
1534
contt               db  'Connected'
1535
contlen:
1536
discontt            db  'Disconnected'
1537
discontlen:
1538
 
1539
cmdOKStr:           db  '200 Command OK',0x0d,0x0a
1540
cmdOKStr_end:
1541
 
1542
loginStr0:          db  '220-  Menuet FTP Server v0.1',0x0d,0x0a
1543
                    db  '220 Username and Password required',0x0d,0x0a
1544
loginStr0_end:
1545
 
1546
loginStr1:          db  '331 Password now required',0x0d,0x0a
1547
loginStr1_end:
1548
 
1549
loginStr2:          db  '230 You are now logged in.',0x0d,0x0a
1550
loginStr2_end:
1551
 
1552
byeStr:             db  '221 Bye bye!',0x0d,0x0a
1553
byeStr_end:
1554
 
1555
systStr:            db  '215 UNIX system type',0x0d,0x0a
1556
systStr_end:
1557
 
1558
ramdir:             db  '257 "/"',0x0d,0x0a
1559
ramdir_end:
1560
 
1561
chdir:              db  '200 directory changed to /',0x0d,0x0a
1562
chdir_end:
1563
 
1564
unsupStr:           db  '500 Unsupported command',0x0d,0x0a
1565
unsupStr_end:
1566
 
1567
noFileStr:          db  '550 No such file',0x0d,0x0a
1568
noFileStr_end:
1569
 
1570
delokStr:           db  '250 DELE command successful',0x0d,0x0a
1571
delokStr_end:
1572
 
1573
startStr:           db  '150 Here it comes...',0x0d,0x0a
1574
startStr_end:
1575
 
1576
storStr:            db  '150 Connecting for STOR',0x0d,0x0a
1577
storStr_end:
1578
 
1579
endStr:             db  '226 Transfer OK, Closing connection',0x0d,0x0a
1580
endStr_end:
1581
 
1582
abortStr:           db  '225 Abort successful',0x0d,0x0a
1583
abortStr_end:
1584
 
1585
 ; This is the buffer used for building up a directory listing line
1586
dirStr:             times 128 db 0
1587
 
1588
; This is template string used in building up a directory listing line
1589
tmplStr:            db 'rw-rw-rw-    1 0        0                ',0
1590
 
1591
months:
1592
        dd     'Jan ','Feb ','Mar ','Apr ','May ','Jun '
1593
        dd     'Jul ','Aug ','Sep ','Oct ','Nov ','Dec '
1594
 
1595
fileinfoblock:
1596
                    dd      0x00
1597
                    dd      0x00
1598
                    dd      0x00
1599
                    dd      0x200         ; bytes to read
1600
                    dd      text + 0x1300 ; data area
1601
filename:           times 256 db 0
1602
 
1603
; The following lines define data for reading a directory block
1604
DirBlocksPerCall = 16
1605
dirinfoblock:
1606
                    dd      1
1607
                    dd      0x00
1608
                    dd      0x00
1609
                    dd      DirBlocksPerCall
1610
                    dd      text + 0x1300   ; data area
1611
; The 'filename' for a directory listing
539 spraid 1612
dirpath             db      '/sys',0
481 diamond 1613
 
1614
fsize:              dd      0
661 ataualpa 1615
 
481 diamond 1616
state               db  0
1617
buffptr             dd  0
1618
buff:               times 256 db 0  ; Could put this after iend
1619
 
1620
; Ram use at the end of the application:
1621
; text                  : 2400 bytes for screen memory
1622
; text + 0x1300          : file data area
1623
text:
1624
I_END: