初始提交:terminalX 可运行态(M0/M1/M1.5 已真机验证)
- M0: libghostty SSH 终端(渲染/输入/连接)+ 白屏修复(OutputGate) + 会话状态机/自动重连 - M1: tsnet 用户态组网 + SSH-over-tsnet(fd 桥),shell 级真机验证;R5(Go+gvisor+C+++Swift 同进程) retire - M1.5: tmux -CC 原生 tab(MVP) - 结构: packages/(TXCore·TXTransport), apps/TerminalX, vendor/(libghostty-spm/libssh2/mbedtls/tsnet-bridge), artifacts/ - 文档: CLAUDE.md + docs/HANDOFF.md(新会话入口) - 环境: 认证代理→依赖 vendor 本地化;Go 在 ~/.local/go;仅模拟器/未签名 - 待续: M2 mosh, tmux 多 pane, M4 安全(host key/SE) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
326
vendor/libssh2/os400/rpg-examples/SFTPXMPLE
vendored
Normal file
326
vendor/libssh2/os400/rpg-examples/SFTPXMPLE
vendored
Normal file
@@ -0,0 +1,326 @@
|
||||
* Example: print a remote ascii file using sftp
|
||||
*
|
||||
h DFTACTGRP(*NO) ACTGRP(*NEW)
|
||||
h OPTION(*NOSHOWCPY)
|
||||
h BNDDIR('LIBSSH2')
|
||||
h BNDDIR('QC2LE')
|
||||
*
|
||||
* Copyright (C) The libssh2 project and its contributors.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* CALL SFTPXMPLE ('<host>' '<port>' '<user>' '<password>' '<filepath>')
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
fQPRINT o f 120 printer
|
||||
*
|
||||
/include LIBSSH2RPG,SSH2_SFTP
|
||||
/include LIBSSH2RPG,SSH2_CCSID
|
||||
*
|
||||
d pi
|
||||
d host 120
|
||||
d port 5
|
||||
d user 20
|
||||
d password 120
|
||||
d filepath 120
|
||||
*
|
||||
**************************************************************************
|
||||
* External definitions
|
||||
**************************************************************************
|
||||
*
|
||||
d atoi pr 10i 0 extproc('atoi')
|
||||
d numstr * value options(*string)
|
||||
*
|
||||
d inet_addr pr 10u 0 extproc('inet_addr')
|
||||
d char_addr * value options(*string)
|
||||
*
|
||||
d socket pr 10i 0 extproc('socket')
|
||||
d domain 10i 0 value
|
||||
d type 10i 0 value
|
||||
d protocol 10i 0 value
|
||||
*
|
||||
d AF_INET c 2
|
||||
d SOCK_STREAM c 1
|
||||
d IPPROTO_IP c 0
|
||||
*
|
||||
d connect pr 10i 0 extproc('connect')
|
||||
d sockfd 10i 0 value
|
||||
d addr * value
|
||||
d addrlen 10u 0 value
|
||||
*
|
||||
d sockaddr_in ds based(######typedef######)
|
||||
d align qualified
|
||||
d sin_family 5i 0
|
||||
d sin_port 5i 0
|
||||
d sin_addr 10u 0
|
||||
d sin_zero 8
|
||||
*
|
||||
d shutdown pr 10i 0 extproc('shutdown')
|
||||
d socket 10i 0 value
|
||||
d how 10i 0 value
|
||||
*
|
||||
d SHUT_RDWR c 2
|
||||
*
|
||||
d qmhsndpm pr extpgm('QMHSNDPM')
|
||||
d msgid 7 const
|
||||
d qmsgfn 20 const
|
||||
d data 999999 const options(*varsize)
|
||||
d datalength 10u 0 const
|
||||
d msgtype 10 const
|
||||
d csentry 999999 const options(*varsize)
|
||||
d cscounter 10u 0 const
|
||||
d msgkey 4
|
||||
d errcode 999999 options(*varsize)
|
||||
d csentrylen 10u 0 const options(*nopass)
|
||||
d csqual 20 const options(*nopass)
|
||||
d waittime 10u 0 const options(*nopass)
|
||||
d csentrytype 10 const options(*nopass)
|
||||
d ccsid 10u 0 const options(*nopass)
|
||||
*
|
||||
**************************************************************************
|
||||
* Constants
|
||||
**************************************************************************
|
||||
*
|
||||
d EBCDIC_CR c X'0D'
|
||||
d EBCDIC_LF c X'25'
|
||||
*
|
||||
**************************************************************************
|
||||
* Global storage
|
||||
**************************************************************************
|
||||
*
|
||||
d sc s * inz(*NULL) String cache
|
||||
d session s * inz(*NULL) Session
|
||||
d sftp_session s * inz(*NULL) LIBSSH2_SFTP *
|
||||
d sftp_handle s * inz(*NULL) LIBSSH2_SFTP_HANDLE*
|
||||
d sin ds likeds(sockaddr_in) Remote IP address
|
||||
d sock s 10i 0 inz(LIBSSH2_INVALID_SOCKET) Socket descriptor
|
||||
d rc s 10i 0 Result code
|
||||
d hostlen s 10u 0 Host name length
|
||||
*
|
||||
**************************************************************************
|
||||
* Main program
|
||||
**************************************************************************
|
||||
|
||||
// Initialize ssh lbrary
|
||||
rc = libssh2_init(0);
|
||||
if rc <> 0;
|
||||
error('libssh2 initialization failed (' + %trim(%char(rc)) + ')');
|
||||
else;
|
||||
// Build remote address
|
||||
sin.sin_family = AF_INET;
|
||||
hostlen = trimmed_length(host: %len(host): %addr(port));
|
||||
if hostlen <> 0;
|
||||
sin.sin_addr = inet_addr(%subst(host: 1: hostlen));
|
||||
else;
|
||||
sin.sin_addr = inet_addr('127.0.0.1');
|
||||
endif;
|
||||
sin.sin_port = atoi(port);
|
||||
if sin.sin_port <= 0;
|
||||
sin.sin_port = 22;
|
||||
endif;
|
||||
sin.sin_zero = *ALLX'00';
|
||||
|
||||
main();
|
||||
cleanout();
|
||||
endif;
|
||||
|
||||
*inlr = *on;
|
||||
/space 3
|
||||
begsr *pssr;
|
||||
cleanout();
|
||||
endsr;
|
||||
/eject
|
||||
**************************************************************************
|
||||
* Main procedure
|
||||
**************************************************************************
|
||||
*
|
||||
p main b
|
||||
*
|
||||
d buf s 1024 Data buffer
|
||||
d nread s 10i 0 Read bytes count
|
||||
|
||||
// Connect to remote server
|
||||
sock = socket(AF_INET: SOCK_STREAM: IPPROTO_IP);
|
||||
if sock = LIBSSH2_INVALID_SOCKET;
|
||||
error('failed to create socket');
|
||||
return;
|
||||
endif;
|
||||
if connect(sock: %addr(sin): %size(sin)) <> 0;
|
||||
error('failed to connect');
|
||||
return;
|
||||
endif;
|
||||
|
||||
// Create a session instance
|
||||
session = libssh2_session_init();
|
||||
if session = *NULL;
|
||||
error('Could not initialize SSH session');
|
||||
return;
|
||||
endif;
|
||||
|
||||
// Since we have set non-blocking, tell libssh2 we are blocking
|
||||
libssh2_session_set_blocking(session: 1);
|
||||
|
||||
// ... start it up. This will trade welcome banners, exchange keys,
|
||||
// and setup crypto, compression, and MAC layers
|
||||
rc = libssh2_session_handshake(session: sock);
|
||||
if rc <> 0;
|
||||
error('Failure establishing SSH session: ' + %trim(%char(rc)));
|
||||
return;
|
||||
endif;
|
||||
|
||||
// Authenticate
|
||||
if libssh2_userauth_password(session:
|
||||
libssh2_from_ccsid(session: sc: 0: user:
|
||||
trimmed_length(user: %size(user):
|
||||
%addr(password)): *omit):
|
||||
libssh2_from_ccsid(session: sc: 0: password:
|
||||
trimmed_length(password: %size(password):
|
||||
%addr(filepath)): *omit)) <> 0;
|
||||
error('Authentication by password failed');
|
||||
return;
|
||||
endif;
|
||||
|
||||
// Request a file via SFTP
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if sftp_session = *NULL;
|
||||
error('Unable to init SFTP session');
|
||||
return;
|
||||
endif;
|
||||
|
||||
sftp_handle = libssh2_sftp_open(sftp_session:
|
||||
libssh2_from_ccsid(session: sc: 0: filepath:
|
||||
trimmed_length(filepath: %size(filepath): *null):
|
||||
*omit): LIBSSH2_FXF_READ: 0);
|
||||
if sftp_handle = *NULL;
|
||||
error('Unable to open file with SFTP: ' +
|
||||
%trim(%char(libssh2_sftp_last_error(sftp_session))));
|
||||
return;
|
||||
endif;
|
||||
|
||||
// Download and display the remote file
|
||||
nread = libssh2_sftp_read(sftp_handle: %addr(buf): %size(buf));
|
||||
dow nread > 0; // loop until we fail
|
||||
print(libssh2_to_ccsid(session: sc: 0: %addr(buf): nread: *omit):
|
||||
-1);
|
||||
libssh2_release_string_cache(session: sc);
|
||||
nread = libssh2_sftp_read(sftp_handle: %addr(buf): %size(buf));
|
||||
enddo;
|
||||
p main e
|
||||
/eject
|
||||
**************************************************************************
|
||||
* Release all allocated resources
|
||||
**************************************************************************
|
||||
*
|
||||
p cleanout b
|
||||
*
|
||||
|
||||
if sftp_handle <> *NULL;
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
endif;
|
||||
|
||||
if sftp_session <> *NULL;
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
endif;
|
||||
|
||||
if session <> *NULL;
|
||||
libssh2_session_disconnect(session: libssh2_from_ccsid(session: sc:
|
||||
0: 'Normal shutdown': -1: *omit));
|
||||
libssh2_release_string_cache(session: sc);
|
||||
libssh2_session_free(session);
|
||||
endif;
|
||||
|
||||
if sock <> LIBSSH2_INVALID_SOCKET;
|
||||
shutdown(sock: SHUT_RDWR);
|
||||
LIBSSH2_SOCKET_CLOSE(sock);
|
||||
endif;
|
||||
|
||||
libssh2_exit();
|
||||
p cleanout e
|
||||
/eject
|
||||
**************************************************************************
|
||||
* Print data line by line
|
||||
**************************************************************************
|
||||
*
|
||||
p print b
|
||||
d pi
|
||||
d string * value options(*string)
|
||||
d len 10i 0 value
|
||||
*
|
||||
d recout ds Output line buffer
|
||||
d lineout 120 inz(*blanks)
|
||||
*
|
||||
d i s 10u 0
|
||||
d j s 10u 0 inz(0)
|
||||
|
||||
if len < 0;
|
||||
len = %len(%str(string));
|
||||
endif;
|
||||
|
||||
for i = 0 to len - 1;
|
||||
if %str(string + i: 1) <> EBCDIC_CR;
|
||||
if %str(string + i: 1) = EBCDIC_LF;
|
||||
write QPRINT recout;
|
||||
lineout = *blanks;
|
||||
j = 0;
|
||||
else;
|
||||
if j >= %size(lineout);
|
||||
write QPRINT recout;
|
||||
lineout = *blanks;
|
||||
j = 0;
|
||||
endif;
|
||||
j = j + 1;
|
||||
%subst(lineout: j: 1) = %str(string + i: 1);
|
||||
endif;
|
||||
endif;
|
||||
endfor;
|
||||
if j > 0;
|
||||
write QPRINT recout;
|
||||
endif;
|
||||
p print e
|
||||
/eject
|
||||
**************************************************************************
|
||||
* Error procedure
|
||||
**************************************************************************
|
||||
*
|
||||
p error b
|
||||
d pi
|
||||
d message * value options(*string)
|
||||
*
|
||||
d errcode ds qualified
|
||||
d provided 10u 0 inz(0)
|
||||
d available 10u 0
|
||||
*
|
||||
d msgkey s 4
|
||||
|
||||
// Send error as an exception to the calling level.
|
||||
qmhsndpm('CPF9898': 'QCPFMSG QSYS':
|
||||
%str(message): %len(%str(message)): '*ESCAPE':
|
||||
'* ': 1: msgkey: errcode);
|
||||
p error e
|
||||
/eject
|
||||
**************************************************************************
|
||||
* Get the length of right-trimmed string
|
||||
**************************************************************************
|
||||
*
|
||||
p trimmed_length b
|
||||
d pi 10u 0
|
||||
d string 999999 options(*varsize)
|
||||
d length 10u 0 value
|
||||
d nextarg * value
|
||||
*
|
||||
d len s 10u 0
|
||||
|
||||
if nextarg <> *null;
|
||||
len = nextarg - %addr(string);
|
||||
if length > len;
|
||||
length = len;
|
||||
endif;
|
||||
endif;
|
||||
len = %scan(X'00': string: 1: length); // Maybe zero-terminated
|
||||
if len = 0;
|
||||
len = length + 1;
|
||||
endif;
|
||||
return %checkr(' ': string: len - 1); // Trim right
|
||||
p trimmed_length e
|
||||
Reference in New Issue
Block a user