📄 mapi.mx
字号:
hdl->prev = NULL; hdl->next = NULL; hdl->mid = NULL; free(hdl); return MOK;}/* Allocate a new connection handle. */static Mapimapi_new(void){ Mapi mid; mid = malloc(sizeof(*mid)); if (mid == NULL) return NULL; assert(mid); /* initialize everything to 0 */ memset(mid, 0, sizeof(*mid)); /* then fill in some details */ mid->auto_commit = 1; mid->error = MOK; mid->hostname = strdup("localhost"); mid->server = NULL; mid->language = strdup("mil"); mid->languageId = LANG_MIL; mid->versionId = 4; mid->noexplain = NULL; mid->motd = NULL; mid->mapiversion = "mapi 1.0"; mid->username = NULL; mid->password = NULL; mid->cachelimit = 100; mid->redircnt = 0; mid->tracelog = NULL; mid->blk.eos = 0; mid->blk.buf = malloc(BLOCK + 1); mid->blk.buf[BLOCK] = 0; mid->blk.buf[0] = 0; mid->blk.nxt = 0; mid->blk.end = 0; mid->blk.lim = BLOCK; mid->first = NULL; return mid;}/* Allocate a new connection handle and fill in the information needed to connect to a server, but don't connect yet. */Mapimapi_mapi(const char *host, int port, const char *username, const char *password, const char *lang, const char *dbname){ Mapi mid; if (!mapi_initialized) { mapi_initialized = 1; if (stream_init() < 0) return NULL; } mid = mapi_new(); if (mid == NULL) return NULL; if (host) { free(mid->hostname); mid->hostname = strdup(host); } if (port == 0) { char *def; if ((def = getenv("MAPIPORT")) != NULL) port = atoi(def); } if (port == 0) port = 50000; /* hardwired default */ /* fill some defaults for user/pass, this should actually never happen */ if (username == NULL) username = "guest"; if (mid->username != NULL) free(mid->username); mid->username = strdup(username); if (password == NULL) password = "guest"; if (mid->password) free(mid->password); mid->password = strdup(password); mid->port = port;#ifdef HAVE_OPENSSL mid->secure = 0;#endif if (lang == NULL) lang = "mil"; free(mid->language); mid->language = strdup(lang); if (strcmp(lang, "mil") == 0) mid->languageId = LANG_MIL; else if (strcmp(lang, "mal") == 0) mid->languageId = LANG_MAL; else if (strcmp(lang, "sql") == 0) mid->languageId = LANG_SQL; else if (strcmp(lang, "xquery") == 0) mid->languageId = LANG_XQUERY; if (mid->database) free(mid->database); mid->database = dbname ? strdup(dbname) : NULL; return mid;}/* Close a connection and free all memory associated with the connection handle. */MapiMsgmapi_destroy(Mapi mid){ mapi_clrError(mid); while (mid->first) mapi_close_handle(mid->first); if (mid->connected) (void) mapi_disconnect(mid); if (mid->blk.buf) free(mid->blk.buf); if (mid->errorstr) free(mid->errorstr); if (mid->hostname) free(mid->hostname); if (mid->username) free(mid->username); if (mid->password) free(mid->password); if (mid->language) free(mid->language); if (mid->database) free(mid->database); if (mid->server) free(mid->server); free(mid); return MOK;}@- Channel ConstructorThe first call of an application is to establish a connection withan already server. The username and password are sent as part ofthe initialization sequence.@c#ifdef HAVE_OPENSSLstatic char *ssl_error(int err, int ret){ char *errstr; char buf[120]; unsigned long e; switch (err) { case SSL_ERROR_ZERO_RETURN: errstr = "TLS/SSL connection has been closed"; break; case SSL_ERROR_WANT_READ: errstr = "The operation did not complete (read)"; break; case SSL_ERROR_WANT_WRITE: errstr = "The operation did not complete (write)"; break; case SSL_ERROR_WANT_X509_LOOKUP: errstr = "The operation did not complete (X509 lookup)"; break; case SSL_ERROR_WANT_CONNECT: errstr = "The operation did not complete (connect)"; break; case SSL_ERROR_SYSCALL: e = ERR_get_error(); if (e == 0) { if (ret == 0) { errstr = "EOF occurred in violation of protocol"; } else if (ret == -1) { /* the underlying BIO reported an I/O error */ errstr = "I/O error"; } else { /* possible? */ errstr = "Some I/O error occurred"; } } else { errstr = ERR_error_string(e, buf); } break; case SSL_ERROR_SSL: e = ERR_get_error(); if (e != 0) errstr = ERR_error_string(e, buf); else { /* possible? */ errstr = "A failure in the SSL library occurred"; } break; default: errstr = "Invalid error code"; } return strdup(errstr);}#endif /* HAVE_OPENSSL *//* (Re-)establish a connection with the server. */static MapiMsgconnect_to_server(Mapi mid){ struct sockaddr_in server;#ifdef HAVE_SYS_UN_H struct sockaddr_un userver;#endif struct sockaddr *serv; socklen_t servsize; SOCKET s;#ifdef HAVE_OPENSSL SSL *ssl = NULL;#endif if (mid->connected) close_connection(mid);#ifdef HAVE_SYS_UN_H if (#ifdef HAVE_OPENSSL !mid->secure &&#endif mid->hostname && mid->hostname[0] == '/') { if (strlen(mid->hostname) >= sizeof(userver.sun_path)) { return mapi_setError(mid, "path name too long", "mapi_reconnect", MERROR); } userver.sun_family = AF_UNIX; strncpy(userver.sun_path, mid->hostname, sizeof(userver.sun_path)); serv = (struct sockaddr *) &userver; servsize = sizeof(userver); } else#endif { struct hostent *hp; hp = gethostbyname(mid->hostname); if (hp == NULL) { return mapi_setError(mid, "gethostbyname failed", "mapi_reconnect", MERROR); } memset(&server, 0, sizeof(server)); memcpy(&server.sin_addr, hp->h_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = htons((unsigned short) (mid->port & 0xFFFF)); serv = (struct sockaddr *) &server; servsize = sizeof(server); }#ifdef HAVE_OPENSSL if (mid->secure && mapi_ssl_ctx == NULL) { mapi_ssl_ctx = SSL_CTX_new(SSLv23_method()); if (mapi_ssl_ctx == 0) { char *errstr = ssl_error(SSL_ERROR_SSL, 0); mapi_setError(mid, errstr, "mapi_reconnect", MERROR); free(errstr); return mid->error; } SSL_CTX_set_verify(mapi_ssl_ctx, SSL_VERIFY_NONE, NULL); }#endif s = socket(serv->sa_family, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return mapi_setError(mid, "Open socket failed", "mapi_reconnect", MERROR); } if (connect(s, serv, servsize) < 0) {#ifdef NATIVE_WIN32 fprintf(stderr, "!ERROR mapi_reconnect: connect: error %d\n", WSAGetLastError());#else perror("!ERROR mapi_reconnect: connect");#endif return mapi_setError(mid, "Setup connection failed", "mapi_reconnect", MERROR); }#ifdef HAVE_OPENSSL if (mid->secure) { if ((ssl = SSL_new(mapi_ssl_ctx)) == 0) { char *errstr = ssl_error(SSL_ERROR_SSL, 0); mapi_setError(mid, errstr, "mapi_reconnect", MERROR); free(errstr); close(s); return mid->error; } if (!SSL_set_fd(ssl, s)) { char *errstr = ssl_error(SSL_ERROR_SSL, 0); mapi_setError(mid, errstr, "mapi_reconnect", MERROR); free(errstr); SSL_free(ssl); close(s); return mid->error; } SSL_set_connect_state(ssl); for (;;) { int ret, err; char *errstr; ret = SSL_connect(ssl); err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* try again */ continue; case SSL_ERROR_NONE: /* successful connect */ break; case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: default: /* some error occurred */ SSL_free(ssl); close(s); errstr = ssl_error(err, ret); mapi_setError(mid, errstr, "mapi_reconnect", MERROR); free(errstr); return mid->error; } break; } mid->to = ssl_wastream(ssl, "Mapi client write"); mid->from = ssl_rastream(ssl, "Mapi client read"); } else#endif { mid->to = socket_wastream(s, "Mapi client write"); mid->from = socket_rastream(s, "Mapi client read"); } check_stream(mid, mid->to, "Cannot open socket for writing", "mapi_reconnect", mid->error); check_stream(mid, mid->from, "Cannot open socket for reading", "mapi_reconnect", mid->error); mid->connected = 1; return MOK;}MapiMsgmapi_start_talking(Mapi mid){ char buf[BLOCK]; size_t len; MapiHdl hdl; int pversion = 0; char *chal; char *server; char *protover; char *rest; mid->to = block_stream(mid->to); check_stream(mid, mid->to, stream_error(mid->to), "mapi_start_talking", mid->error); mid->from = block_stream(mid->from); check_stream(mid, mid->from, stream_error(mid->from), "mapi_start_talking", mid->error); /* consume server challenge */ len = stream_read_block(mid->from, buf, 1, BLOCK); check_stream(mid, mid->from, "Connection terminated", "mapi_start_talking", (mid->blk.eos = 1, mid->error)); assert(len < BLOCK); /* buf at this point looks like "challenge:servertype:protover[:.*]" */ chal = buf; server = strchr(chal, ':'); if (server == NULL) { mapi_setError(mid, "Challenge string is not valid", "mapi_start_talking", MERROR); return mid->error; } *server++ = '\0'; protover = strchr(server, ':'); if (protover == NULL) { mapi_setError(mid, "Challenge string is not valid", "mapi_start_talking", MERROR); return mid->error; } *protover++ = '\0'; rest = strchr(protover, ':'); if (rest != NULL) { *rest++ = '\0'; } pversion = atoi(protover); if (pversion < 8) { /* because the headers changed, and because it makes no sense to * try and be backwards compatible, we bail out with a friendly * message saying so. */ snprintf(buf, BLOCK, "Unsupported protocol version: %d. " "This client only supports version 8 and up. " "Sorry, can't help you here!", pversion); mapi_setError(mid, buf, "mapi_start_talking", MERROR); return mid->error; } else if (pversion == 8) { char* hash = NULL; char* hashes = NULL; /* the database has sent a list of supported hashes to us, it's * in the form of a comma separated list and in the variable * rest. We try to use the strongest algorithm. */ hashes = rest; hash = strchr(hashes, ':'); /* temp misuse hash */ if (hash) { *hash = '\0'; rest = hash + 1; } hash = NULL; /* TODO: make this actually obey the separation by comm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -