/* SPDX-License-Identifier: LGPL-3.0-or-later */ /* * Copyright (C) 2008 Banco do Brasil S.A. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ANDROID #include #endif // !ANDROID #include #include "kybdc.h" #include "ansic.h" #include "togglesc.h" #include "screen.h" #include "screenc.h" #include "ctlrc.h" #include "ftc.h" #include "kybdc.h" #include "3270ds.h" #include "popupsc.h" #include #include #include /*---[ Globals ]--------------------------------------------------------------------------------------------------------------*/ static H3270 *default_session = NULL; /*---[ Statics ]--------------------------------------------------------------------------------------------------------------*/ /*---[ Implement ]------------------------------------------------------------------------------------------------------------*/ /** * @brief Closes a TN3270 session releasing resources. * * @param h handle of the session to close. * */ void lib3270_session_free(H3270 *h) { size_t f; if(!h) return; if(lib3270_is_connected(h)) { // Connected, disconnect lib3270_disconnect(h); } else if(lib3270_get_connection_state(h) == LIB3270_CONNECTING) { // Connecting, disconnect debug("%s: Stopping while connecting",__FUNCTION__); lib3270_disconnect(h); } // Do we have pending tasks? if(h->tasks) { lib3270_write_log(h,LIB3270_STRINGIZE_VALUE_OF(PRODUCT_NAME),"Destroying session with %u active task(s)",h->tasks); } shutdown_toggles(h); // Release network module if(h->network.module) { h->network.module->finalize(h); h->network.module = NULL; } // Release state change callbacks for(f=0; flisteners.state[f]); // Release toggle change listeners. for(f=0; flisteners.toggle[f]); // Release action listeners. for(f=0; flisteners.actions[f]); // Release Lu names if(h->lu.names) { lib3270_free(h->lu.names); h->lu.names = NULL; } // Release memory #define release_pointer(x) lib3270_free(x); x = NULL; // release_pointer(h->charset.display); release_pointer(h->paste_buffer); release_pointer(h->ibuf); h->ibuf_size = 0; for(f=0; f<(sizeof(h->buffer)/sizeof(h->buffer[0])); f++) { release_pointer(h->buffer[f]); } if(h == default_session) default_session = NULL; // Release hostname info release_pointer(h->host.current); release_pointer(h->host.url); release_pointer(h->host.srvc); release_pointer(h->host.qualified); release_pointer(h->charset.host); release_pointer(h->charset.display); release_pointer(h->text); release_pointer(h->zero_buf); release_pointer(h->output.base); release_pointer(h->sbbuf); release_pointer(h->tabs); // Release timeouts lib3270_linked_list_free(&h->timeouts); // Release inputs; lib3270_linked_list_free(&h->input.list); // Release logfile release_pointer(h->log.file); release_pointer(h->trace.file); lib3270_free(h); } static void nop_void() { } static int default_action(H3270 GNUC_UNUSED(*hSession), const char GNUC_UNUSED(*name)) { return errno = ENOENT; } /* static void update_char(H3270 GNUC_UNUSED(*session), int GNUC_UNUSED(addr), unsigned char GNUC_UNUSED(chr), unsigned short GNUC_UNUSED(attr), unsigned char GNUC_UNUSED(cursor)) { } static void update_model(H3270 GNUC_UNUSED(*session), const char GNUC_UNUSED(*name), int GNUC_UNUSED(model), int GNUC_UNUSED(rows), int GNUC_UNUSED(cols)) { } static void changed(H3270 GNUC_UNUSED(*session), int GNUC_UNUSED(bstart), int GNUC_UNUSED(bend)) { } static void update_cursor(H3270 GNUC_UNUSED(*session), unsigned short GNUC_UNUSED(row), unsigned short GNUC_UNUSED(col), unsigned char GNUC_UNUSED(c), unsigned short GNUC_UNUSED(attr)) { } static void update_oia(H3270 GNUC_UNUSED(*session), LIB3270_FLAG GNUC_UNUSED(id), unsigned char GNUC_UNUSED(on)) { } static void update_selection(H3270 GNUC_UNUSED(*session), int GNUC_UNUSED(start), int GNUC_UNUSED(end)) { } static void set_cursor(H3270 GNUC_UNUSED(*session), LIB3270_POINTER GNUC_UNUSED(id)) { } static void update_ssl(H3270 GNUC_UNUSED(*session), LIB3270_SSL_STATE GNUC_UNUSED(state)) { } static void set_timer(H3270 GNUC_UNUSED(*session), unsigned char GNUC_UNUSED(on)) { } static void default_update_luname(H3270 GNUC_UNUSED(*session), const char GNUC_UNUSED(*name)) { } static void default_update_url(H3270 GNUC_UNUSED(*session), const char GNUC_UNUSED(*url)) { } */ static int print(H3270 *session, LIB3270_CONTENT_OPTION GNUC_UNUSED(mode)) { lib3270_write_log(session, "print", "%s", "Printing is unavailable"); lib3270_popup_dialog(session, LIB3270_NOTIFY_WARNING, _( "Can't print" ), _( "Unable to print" ), "%s", strerror(ENOTSUP)); return errno = ENOTSUP; } static int save(H3270 *session, LIB3270_CONTENT_OPTION GNUC_UNUSED(mode), const char GNUC_UNUSED(*filename)) { lib3270_write_log(session, "save", "%s", "Saving is unavailable"); lib3270_popup_dialog(session, LIB3270_NOTIFY_WARNING, _( "Can't save" ), _( "Unable to save" ), "%s", strerror(ENOTSUP)); return errno = ENOTSUP; } static int load(H3270 *session, const char GNUC_UNUSED(*filename)) { lib3270_write_log(session, "load", "%s", "Loading from file is unavailable"); lib3270_popup_dialog(session, LIB3270_NOTIFY_WARNING, _( "Can't load" ), _( "Unable to load from file" ), "%s", strerror(ENOTSUP)); return errno = ENOTSUP; } static void screen_disp(H3270 *session) { CHECK_SESSION_HANDLE(session); screen_update(session,0,session->view.rows*session->view.cols); } void lib3270_reset_callbacks(H3270 *hSession) { // Default calls memset(&hSession->cbk,0,sizeof(hSession->cbk)); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" hSession->cbk.update = nop_void; hSession->cbk.update_model = nop_void; hSession->cbk.update_cursor = nop_void; hSession->cbk.set_selection = nop_void; hSession->cbk.ctlr_done = nop_void; hSession->cbk.changed = nop_void; hSession->cbk.erase = screen_disp; hSession->cbk.suspend = nop_void; hSession->cbk.resume = screen_disp; hSession->cbk.update_oia = nop_void; hSession->cbk.update_selection = nop_void; hSession->cbk.cursor = nop_void; hSession->cbk.update_ssl = nop_void; hSession->cbk.display = screen_disp; hSession->cbk.set_width = nop_void; hSession->cbk.update_status = nop_void; hSession->cbk.autostart = nop_void; hSession->cbk.set_timer = nop_void; hSession->cbk.print = print; hSession->cbk.save = save; hSession->cbk.load = load; hSession->cbk.update_luname = nop_void; hSession->cbk.update_url = nop_void; hSession->cbk.action = default_action; hSession->cbk.reconnect = lib3270_reconnect; hSession->cbk.word_selected = nop_void; #pragma GCC diagnostic pop lib3270_set_popup_handler(hSession, NULL); lib3270_set_log_handler(hSession,NULL,NULL); lib3270_set_trace_handler(hSession,NULL,NULL); } static void lib3270_session_init(H3270 *hSession, const char *model, const char *charset) { int f; memset(hSession,0,sizeof(H3270)); lib3270_set_default_network_module(hSession); #if defined(SSL_ENABLE_CRL_CHECK) hSession->ssl.download_crl = 1; #endif // SSL_ENABLE_CRL_CHECK lib3270_set_host_charset(hSession,charset); lib3270_reset_callbacks(hSession); // Set the defaults. hSession->extended = 1; hSession->typeahead = 1; hSession->oerr_lock = 1; hSession->unlock_delay = 1; hSession->icrnl = 1; hSession->onlcr = 1; hSession->model_num = -1; hSession->connection.state = LIB3270_NOT_CONNECTED; hSession->connection.timeout = 10000; hSession->connection.retry = 5000; hSession->oia.status = LIB3270_MESSAGE_DISCONNECTED; hSession->kybdlock = KL_NOT_CONNECTED; hSession->aid = AID_NO; hSession->reply_mode = SF_SRM_FIELD; hSession->linemode = 1; hSession->tn3270e_submode = E_NONE; hSession->scroll_top = -1; hSession->scroll_bottom = -1; hSession->wraparound_mode = 1; hSession->saved_wraparound_mode = 1; hSession->once_cset = -1; hSession->state = LIB3270_ANSI_STATE_DATA; hSession->host_type = LIB3270_HOSTTYPE_DEFAULT; hSession->colors = 16; hSession->m3279 = 1; hSession->pointer = (unsigned short) LIB3270_POINTER_LOCKED; #ifdef UNLOCK_MS lib3270_set_unlock_delay(hSession,UNLOCK_MS); #else lib3270_set_unlock_delay(hSession,350); #endif // UNLOCK_MS // CSD for(f=0; f<4; f++) hSession->csd[f] = hSession->saved_csd[f] = LIB3270_ANSI_CSD_US; #ifdef _WIN32 // Get defaults from registry. { lib3270_auto_cleanup(HKEY) hKey = 0; DWORD disp = 0; LSTATUS rc = RegCreateKeyEx( HKEY_LOCAL_MACHINE, "Software\\" LIB3270_STRINGIZE_VALUE_OF(PRODUCT_NAME) "\\protocol", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE|KEY_READ, NULL, &hKey, &disp); if(rc == ERROR_SUCCESS) { size_t property; const LIB3270_UINT_PROPERTY * uiProps = lib3270_get_unsigned_properties_list(); for(property = 0; uiProps[property].name; property++) { if(!(uiProps[property].set && uiProps[property].group == LIB3270_ACTION_GROUP_OFFLINE)) continue; DWORD val = (DWORD) uiProps[property].default_value; DWORD cbData = sizeof(DWORD); DWORD dwRet = RegQueryValueEx(hKey, uiProps[property].name, NULL, NULL, (LPBYTE) &val, &cbData); if(dwRet == ERROR_SUCCESS) { debug("%s=%u",uiProps[property].name,(unsigned int) val); uiProps[property].set(hSession,(unsigned int) val); } else { uiProps[property].set(hSession,uiProps[property].default_value); } } } } #endif // _WIN32 // Initialize toggles initialize_toggles(hSession); lib3270_set_model_name(hSession,model); } H3270 * lib3270_session_new(const char *model) { H3270 * hSession; trace("%s - configured=%s",__FUNCTION__,default_session ? "Yes" : "No"); hSession = lib3270_malloc(sizeof(H3270)); lib3270_session_init(hSession, model, "bracket" ); if(!default_session) default_session = hSession; if(screen_init(hSession)) return NULL; trace("%s: Initializing KYBD",__FUNCTION__); lib3270_register_schange(hSession,LIB3270_STATE_CONNECT,kybd_connect,NULL); lib3270_register_schange(hSession,LIB3270_STATE_3270_MODE,kybd_in3270,NULL); #if defined(X3270_ANSI) trace("%s: Initializing ANSI",__FUNCTION__); lib3270_register_schange(hSession,LIB3270_STATE_3270_MODE,ansi_in3270,NULL); #endif // X3270_ANSI #if defined(X3270_FT) ft_init(hSession); #endif lib3270_set_url(hSession,NULL); // Set default URL (if available). trace("%s finished",__FUNCTION__); errno = 0; return hSession; } #if defined(DEBUG) void check_session_handle(H3270 **hSession, const char *fname) #else void check_session_handle(H3270 **hSession) #endif // DEBUG { if(*hSession) return; // *hSession = lib3270_get_default_session_handle(); #if defined(DEBUG) lib3270_write_log(NULL, "lib3270", "%s called with empty session from %s",__FUNCTION__,fname); #else lib3270_write_log(NULL, "lib3270", "%s called with empty session",__FUNCTION__); #endif // ANDROID } LIB3270_INTERNAL int check_online_session(const H3270 *hSession) { // Is the session valid? if(!hSession) return errno = EINVAL; // Is it connected? if((int) hSession->connection.state < (int)LIB3270_CONNECTED_INITIAL) return errno = ENOTCONN; return 0; } LIB3270_INTERNAL int check_offline_session(const H3270 *hSession) { // Is the session valid? if(!hSession) return errno = EINVAL; // Is it connected? if((int) hSession->connection.state >= (int)LIB3270_CONNECTED_INITIAL) return errno = EISCONN; return 0; } LIB3270_EXPORT H3270 * lib3270_get_default_session_handle(void) { if(default_session) return default_session; return lib3270_session_new(""); } LIB3270_EXPORT void lib3270_set_user_data(H3270 *h, void *ptr) { CHECK_SESSION_HANDLE(h); h->user_data = ptr; } LIB3270_EXPORT void * lib3270_get_user_data(H3270 *h) { CHECK_SESSION_HANDLE(h); return h->user_data; } LIB3270_EXPORT void lib3270_set_session_id(H3270 *hSession, char id) { CHECK_SESSION_HANDLE(hSession); hSession->id = id; } LIB3270_EXPORT char lib3270_get_session_id(H3270 *hSession) { CHECK_SESSION_HANDLE(hSession); return hSession->id; } struct lib3270_session_callbacks * lib3270_get_session_callbacks(H3270 *hSession, const char *revision, unsigned short sz) { #define REQUIRED_REVISION "20211118" if(revision && strcasecmp(revision,REQUIRED_REVISION) < 0) { errno = EINVAL; lib3270_write_log(hSession,PACKAGE_NAME,"Invalid revision %s when setting callback table",revision); return NULL; } if(sz != sizeof(struct lib3270_session_callbacks)) { lib3270_write_log(hSession,PACKAGE_NAME,"Invalid callback table (sz=%u expected=%u)",sz,(unsigned int) sizeof(struct lib3270_session_callbacks)); errno = EINVAL; return NULL; } return &hSession->cbk; }