Send data to an FTP server

Good day all,

I haven’t posted in awhile. Getting close to retirement. My c63 ABC multi-dll veterinary app is very stable and I get few questions, a good thing.

Recently a user asked if I could upload data to an FTP site. I don’t anticipate downloading anything from an FTP site. I have not done anything like this in a very long time if at all. I looked through stuff presented here but didn’t find too much.

I wonder if any of you could point me to documentation or offer some guidance as to how I can best learn how to add something to my app. The only third party product I am using is vuMail to send e-mails.

Thank you for any guidance provided.
Regards,
Doug Selzler

you can use LibCurl.

C6 is getting a bit old in the tooth. Most of the things I’d recommend are no longer supported (eg Nettalk)
I’d suggest using RUN() to run an FTP Client of some sort. eg the windows built in FTP, or CURL

I would check out Mike’s Libcurl wrapper first. GitHub - mikeduglas/libcurl: libcurl for Clarion

Use LibCurl from Mike.
I have made some C6.3 App examples that is available on his site.

LibCurl is your bet. I use it.

I use WinSCP scripts for years. I start the script over a BAT-File

winscp.com /ini=nul /script=script.scp
if %ERRORLEVEL% neq 0 goto error
copy 20*.txt .\Log
del 20*.txt
:error
exit

The script here manage the upload for all 20*.txt files. I use scripts for downloads too. I start the BAT-File with the PowerRun-Templates to minimize or hide the poping CMD-Windows.

Good morning all,

Thank you to everyone who replied so quickly to my FTP question. I started looking at Mike’s extensive libcurl material on GitHub this morning. There is much to wade through. I will surely have more questions. I’m getting rusty as I haven’t made any changes to my veterinary app in a couple of years. c6.3 is the end of the line for me.

I get the impression from user conversation that many of them have retired or are very close. We are aging out together. I will continue to support the app as long as users ask for help or I am able. It’s been a good run.

Thank you Mr. Duglas for for so generously providing all this material to the Clarion community.

Best regards to all,
Doug

1 Like

Hi Doug

I use the Socket Tools library but if its straight FTP you can do this directly within Clarion 6.3
What country are you in - I’m in the UK and my daughter in law is a vet

I’m 70 now but still busy writing code

Let me know if you would like more info

Jon

Hi Jon,

Thank you for your reply. I’m in the US, Colorado, 78 and still active.

My veterinary app focusses on the equine racetrack practitioner. It’s an interesting data environment. Owners and trainers are constantly changing ownership and or shares and informing the vet sometimes weeks even months later so lots of billed transactions have to be frequently adjusted which I handle progammatically. The software tracks medical activity as well as produce practice analysis.

I haven’t needed to export much data so integrating an FTP functionality into the app is new to me. I seem to remember doing some stand alone FTP transfers many many years ago. I would appreciate any additional guidance / suggestions that you might offer.

I have started to study the libcurl material on GitHub suggested earlier as well as the WinSCP suggestion from Joei. I might need a little hand holding.

Thanks again you for your reply.
–Doug

Hi Doug,

You are doing well - As I mentioned I’m 70 now I think by the time I get to 78 if I get there I’ll be probably just doing support and no new coding
I write some Medical Imaging software mostly for humans but one of the instruments is used by Vets as well Vantage Plus - Binocular indirect ophthalmoscopes - Diagnostic equipment (keelerusa.com)
This is not written in Clarion though
The other product is Sailwave for scoring and publishing Yacht races - This is written in Clarion

This is the code from Clarion 6 that uploads files using FTP

winineth = InternetOpen(zApp,INTERNET_OPEN_TYPE_DIRECT,zNull,zNull,0)
IF ~winineth
Message('Cannot initialise an internet connection')
ELSE
zServer = Clip('[ftp.sailwave.com](https://mailtrack.io/l/82fb6c6a216537be1c6f4b4f880099e280046987?url=http%3A%2F%2Fftp.sailwave.com&u=2430811&signature=397674d1246f7811)')

zUser = Clip('[[email protected]](mailto:[email protected])')
zPassword = Clip('xxxxxxxxx')
OnceMsg('Wininet','Possible delay...','It can take a few seconds to connect to the remote computer; long enough to start thinking nothing has happened...')

IF NullString(OptFtpPort)
Port# = INTERNET_DEFAULT_FTP_PORT
ELSE
Port# = OptFtpPort
END
IF OptFtpPassive
Flag# = INTERNET_FLAG_PASSIVE
ELSE
Flag# = INTERNET_FLAG_ACTIVE
END
connecth = InternetConnect(winineth,zServer,Port#,zUser,zPassword,INTERNET_SERVICE_FTP,Flag#,0)

MonSync()
IF ~connecth
MyMessage('Cannot connect to ' & zServer)
InternetCloseHandle(winineth)
ELSE
zSrcFile = Clip(GlobalFileName)
zDstFile = Clip(SerFtpFile)

MyMessage('Connection to ' & Clip(zServer) & ' to write ' & Clip(zDstFile) & ' established. Click OK to continue...')

Err = FtpPutFile(connecth,zSrcFile,zDstFile,FTP_TRANSFER_TYPE_ASCII,0)

InternetCloseHandle(connecth)
InternetCloseHandle(winineth)
IF ~Err
MyMessage('Failed to upload page to ' & Clip(OptFtpServer))
ELSE

MyMessage('Page uploaded to ' & Clip(OptFtpServer) & ' as ' & Clip(SerFtpFile) & ' OK.')

END
END
END

The WinInet definitions are

MODULE('wininet')
InternetSetStatusCallback(long,long),long,raw,pascal,name('InternetSetStatusCallbackA')
InternetAttemptConnect(Long),long,raw,pascal
InternetOpen(*cstring,long,*cstring,*cstring,long),long,raw,pascal,name('InternetOpenA')
InternetOpenUrl(long,*cstring,*cstring,long,long,long),long,raw,pascal,name('InternetOpenUrlA')
InternetReadFile(long,*cstring,long,*long),long,raw,pascal
InternetCloseHandle(long),long,raw,pascal,proc!,name
InternetFindNextFile(long,win32_find_data_def),long,raw,pascal,name('InternetFindNextFileA')
InternetConnect(long,*cstring,long,*cstring,*cstring,long,long,long),long,raw,pascal,name('InternetConnectA')
InternetGetLastResponseInfo(long,*cstring,long),long,raw,pascal,name('InternetGetLastResponseInfoA')
FtpGetCurrentDirectory(long,*cstring,*long),long,raw,pascal,name('FtpGetCurrentDirectoryA')
FtpSetCurrentDirectory(long,*cstring),long,raw,pascal,name('FtpSetCurrentDirectoryA')
FtpCreateDirectory(long,*cstring),long,raw,pascal,name('FtpCreateDirectoryA')
FtpRemoveDirectory(long,*cstring),long,raw,pascal,name('FtpRemoveDirectoryA')
FtpDeleteFile(long,*cstring),long,raw,pascal,name('FtpDeleteFileA')
FtpRenameFile(long,*cstring,*cstring),long,raw,pascal,name('FtpRenameFileA')
FtpGetFile(long,*cstring,*cstring,long,long,long,long),long,raw,pascal,name('FtpGetFileA')
FtpPutFile(long,*cstring,*cstring,long,long),long,raw,pascal,name('FtpPutFileA')
FtpFindFirstFile(long,*cstring,win32_find_data_def,long,long),long,raw,pascal,name('FtpFindFirstFileA')
FtpOpenFile(long,*cstring,long,long,long),long,raw,pascal,name('FtpOpenFileA')
FtpGetFileSize(long,long),long,raw,pascal
InternetQueryOption(long,long,*cstring,long),long,raw,pascal,name('InternetQueryOptionA')

InternetSetOption(long,long,long,long),long,raw,pascal,name('InternetSetOptionA')
InternetGetOption(long,long,long,long),long,raw,pascal,name('InternetQueryOptionA')
END

!wininet constants
INTERNET_OPTION_CONNECTED_STATE EQUATE(50)
INTERNET_STATE_CONNECTED EQUATE(1)
INTERNET_STATE_DISCONNECTED EQUATE(2)
INTERNET_STATE_DISCONNECTED_BY_USER EQUATE(010H)
INTERNET_STATE_IDLE EQUATE(0100H)
INTERNET_STATE_BUSY EQUATE(0200H)

INTERNET_OPEN_TYPE_PRECONFIG EQUATE(0)
INTERNET_OPEN_TYPE_DIRECT EQUATE(1)
INTERNET_OPEN_TYPE_PROXY EQUATE(3)

INTERNET_FLAG_ACTIVE EQUATE(0h)
INTERNET_FLAG_PASSIVE EQUATE(08000000h)
INTERNET_FLAG_ASYNC EQUATE(010000000h)
INTERNET_FLAG_RELOAD EQUATE(080000000h)
INTERNET_FLAG_NO_CACHE_WRITE EQUATE(04000000h)
INTERNET_FLAG_DONT_CACHE EQUATE(04000000h)
INTERNET_FLAG_MAKE_PERSISTENT EQUATE(02000000h)
INTERNET_FLAG_FROM_CACHE EQUATE(01000000h)
INTERNET_FLAG_OFFLINE EQUATE(01000000h)
INTERNET_FLAG_SECURE EQUATE(0800000h)
INTERNET_FLAG_KEEP_CONNECTION EQUATE(0400000h)
INTERNET_FLAG_NO_AUTO_REDIRECT EQUATE(0200000h)
INTERNET_FLAG_READ_PREFETCH EQUATE(0100000h)
INTERNET_FLAG_NO_COOKIES EQUATE(080000h)
INTERNET_FLAG_NO_AUTH EQUATE(040000h)
INTERNET_FLAG_CACHE_IF_NET_FAIL EQUATE(010000h)

WININET_API_FLAG_SYNC equate(4)

INTERNET_DEFAULT_FTP_PORT EQUATE(21)
INTERNET_DEFAULT_GOPHER_PORT EQUATE(70)
INTERNET_DEFAULT_HTTP_PORT EQUATE(80)
INTERNET_DEFAULT_HTTPS_PORT EQUATE(443)
INTERNET_DEFAULT_SOCKS_PORT EQUATE(1080)

INTERNET_SERVICE_FTP EQUATE(1)
FTP_TRANSFER_TYPE_UNKNOWN EQUATE(0)
FTP_TRANSFER_TYPE_ASCII EQUATE(1)
FTP_TRANSFER_TYPE_BINARY EQUATE(2)

INTERNET_INVALID_STATUS_CALLBACK EQUATE( -1)

FLAGS_ERROR_UI_FILTER_FOR_ERRORS EQUATE( 1)
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS EQUATE( 2)
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA EQUATE( 4)
FLAGS_ERROR_UI_FLAGS_NO_UI EQUATE( 8)
FLAGS_ERROR_UI_SERIALIZE_DIALOGS EQUATE( 10h)

INTERNET_STATUS_RESOLVING_NAME EQUATE( 10)
INTERNET_STATUS_NAME_RESOLVED EQUATE( 11)
INTERNET_STATUS_CONNECTING_TO_SERVER EQUATE( 20)
INTERNET_STATUS_CONNECTED_TO_SERVER EQUATE( 21)
INTERNET_STATUS_SENDING_REQUEST EQUATE( 30)
INTERNET_STATUS_REQUEST_SENT EQUATE( 31)
INTERNET_STATUS_RECEIVING_RESPONSE EQUATE( 40)
INTERNET_STATUS_RESPONSE_RECEIVED EQUATE( 41)
INTERNET_STATUS_CTL_RESPONSE_RECEIVED EQUATE( 42)
INTERNET_STATUS_PREFETCH EQUATE( 43)
INTERNET_STATUS_CLOSING_CONNECTION EQUATE( 50)
INTERNET_STATUS_CONNECTION_CLOSED EQUATE( 51)
INTERNET_STATUS_HANDLE_CREATED EQUATE( 60)
INTERNET_STATUS_HANDLE_CLOSING EQUATE( 70)
INTERNET_STATUS_REQUEST_COMPLETE EQUATE( 100)
INTERNET_STATUS_REDIRECT EQUATE( 110)
INTERNET_STATUS_INTERMEDIATE_RESPONSE EQUATE( 120)
INTERNET_STATUS_STATE_CHANGE EQUATE( 200)

INTERNET_ERROR_BASE EQUATE( 12000)
ERROR_INTERNET_OUT_OF_HANDLES EQUATE(INTERNET_ERROR_BASE + 1)
ERROR_INTERNET_TIMEOUT EQUATE(INTERNET_ERROR_BASE + 2)
ERROR_INTERNET_EXTENDED_ERROR EQUATE(INTERNET_ERROR_BASE + 3)
ERROR_INTERNET_INTERNAL_ERROR EQUATE(INTERNET_ERROR_BASE + 4)
ERROR_INTERNET_INVALID_URL EQUATE(INTERNET_ERROR_BASE + 5)
ERROR_INTERNET_UNRECOGNIZED_SCHEME EQUATE(INTERNET_ERROR_BASE + 6)
ERROR_INTERNET_NAME_NOT_RESOLVED EQUATE(INTERNET_ERROR_BASE + 7)
ERROR_INTERNET_PROTOCOL_NOT_FOUND EQUATE(INTERNET_ERROR_BASE + 8)
ERROR_INTERNET_INVALID_OPTION EQUATE(INTERNET_ERROR_BASE + 9)
ERROR_INTERNET_BAD_OPTION_LENGTH EQUATE(INTERNET_ERROR_BASE + 10)
ERROR_INTERNET_OPTION_NOT_SETTABLE EQUATE(INTERNET_ERROR_BASE + 11)
ERROR_INTERNET_SHUTDOWN EQUATE(INTERNET_ERROR_BASE + 12)
ERROR_INTERNET_INCORRECT_USER_NAME EQUATE(INTERNET_ERROR_BASE + 13)
ERROR_INTERNET_INCORRECT_PASSWORD EQUATE(INTERNET_ERROR_BASE + 14)
ERROR_INTERNET_LOGIN_FAILURE EQUATE(INTERNET_ERROR_BASE + 15)
ERROR_INTERNET_INVALID_OPERATION EQUATE(INTERNET_ERROR_BASE + 16)
ERROR_INTERNET_OPERATION_CANCELLED EQUATE(INTERNET_ERROR_BASE + 17)
ERROR_INTERNET_INCORRECT_HANDLE_TYPE EQUATE(INTERNET_ERROR_BASE + 18)
ERROR_INTERNET_INCORRECT_HANDLE_STATE EQUATE(INTERNET_ERROR_BASE + 19)
ERROR_INTERNET_NOT_PROXY_REQUEST EQUATE(INTERNET_ERROR_BASE + 20)
ERROR_INTERNET_REGISTRY_VALUE_NOT_FOUND EQUATE(INTERNET_ERROR_BASE + 21)
ERROR_INTERNET_BAD_REGISTRY_PARAMETER EQUATE(INTERNET_ERROR_BASE + 22)
ERROR_INTERNET_NO_DIRECT_ACCESS EQUATE(INTERNET_ERROR_BASE + 23)
ERROR_INTERNET_NO_CONTEXT EQUATE(INTERNET_ERROR_BASE + 24)
ERROR_INTERNET_NO_CALLBACK EQUATE(INTERNET_ERROR_BASE + 25)
ERROR_INTERNET_REQUEST_PENDING EQUATE(INTERNET_ERROR_BASE + 26)
ERROR_INTERNET_INCORRECT_FORMAT EQUATE(INTERNET_ERROR_BASE + 27)
ERROR_INTERNET_ITEM_NOT_FOUND EQUATE(INTERNET_ERROR_BASE + 28)
ERROR_INTERNET_CANNOT_CONNECT EQUATE(INTERNET_ERROR_BASE + 29)
ERROR_INTERNET_CONNECTION_ABORTED EQUATE(INTERNET_ERROR_BASE + 30)
ERROR_INTERNET_CONNECTION_RESET EQUATE(INTERNET_ERROR_BASE + 31)
ERROR_INTERNET_FORCE_RETRY EQUATE(INTERNET_ERROR_BASE + 32)
ERROR_INTERNET_INVALID_PROXY_REQUEST EQUATE(INTERNET_ERROR_BASE + 33)
ERROR_INTERNET_NEED_UI EQUATE(INTERNET_ERROR_BASE + 34)
ERROR_INTERNET_HANDLE_EXISTS EQUATE(INTERNET_ERROR_BASE + 36)
ERROR_INTERNET_SEC_CERT_DATE_INVALID EQUATE(INTERNET_ERROR_BASE + 37)
ERROR_INTERNET_SEC_CERT_CN_INVALID EQUATE(INTERNET_ERROR_BASE + 38)
ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR EQUATE(INTERNET_ERROR_BASE + 39)
ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR EQUATE(INTERNET_ERROR_BASE + 40)
ERROR_INTERNET_MIXED_SECURITY EQUATE(INTERNET_ERROR_BASE + 41)
ERROR_INTERNET_CHG_POST_IS_NON_SECURE EQUATE(INTERNET_ERROR_BASE + 42)
ERROR_INTERNET_POST_IS_NON_SECURE EQUATE(INTERNET_ERROR_BASE + 43)
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED EQUATE(INTERNET_ERROR_BASE + 44)
ERROR_INTERNET_INVALID_CA EQUATE(INTERNET_ERROR_BASE + 45)
ERROR_INTERNET_CLIENT_AUTH_NOT_SETUP EQUATE(INTERNET_ERROR_BASE + 46)
ERROR_INTERNET_ASYNC_THREAD_FAILED EQUATE(INTERNET_ERROR_BASE + 47)
ERROR_INTERNET_REDIRECT_SCHEME_CHANGE EQUATE(INTERNET_ERROR_BASE + 48)
ERROR_INTERNET_DIALOG_PENDING EQUATE(INTERNET_ERROR_BASE + 49)
ERROR_INTERNET_RETRY_DIALOG EQUATE(INTERNET_ERROR_BASE + 50)
ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR EQUATE(INTERNET_ERROR_BASE + 52)
ERROR_INTERNET_INSERT_CDROM EQUATE(INTERNET_ERROR_BASE + 53)

ERROR_HTTP_HEADER_NOT_FOUND EQUATE(INTERNET_ERROR_BASE + 150)
ERROR_HTTP_DOWNLEVEL_SERVER EQUATE(INTERNET_ERROR_BASE + 151)
ERROR_HTTP_INVALID_SERVER_RESPONSE EQUATE(INTERNET_ERROR_BASE + 152)
ERROR_HTTP_INVALID_HEADER EQUATE(INTERNET_ERROR_BASE + 153)
ERROR_HTTP_INVALID_QUERY_REQUEST EQUATE(INTERNET_ERROR_BASE + 154)
ERROR_HTTP_HEADER_ALREADY_EXISTS EQUATE(INTERNET_ERROR_BASE + 155)
ERROR_HTTP_REDIRECT_FAILED EQUATE(INTERNET_ERROR_BASE + 156)
ERROR_HTTP_NOT_REDIRECTED EQUATE(INTERNET_ERROR_BASE + 160)
ERROR_HTTP_COOKIE_NEEDS_CONFIRMATION EQUATE(INTERNET_ERROR_BASE + 161)
ERROR_HTTP_COOKIE_DECLINED EQUATE(INTERNET_ERROR_BASE + 162)
ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION EQUATE(INTERNET_ERROR_BASE + 168)

For the latest version of Sailwave www.sailwave.com I use the Socket Tools library as that handles all the secure FTP and other web transfer types

Hope that is helpful

Regards

Jon

Dear Doug
Do you know how to include an .Inc file onto your application?
And, having done that, do you know how to instatiate a class object from that file?
If the answer to these is Yes, I may be able to help you out with a 20+ year old FTP object I created for C55, it uses wininet, is very basic, but works.
Julian