📄 ft.c
字号:
/* * File transfer (OFT) and DirectIM (ODC). * (OSCAR File Transfer, Oscar Direct Connect(ion?) */#define FAIM_INTERNAL#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <aim.h>#ifndef _WIN32#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/utsname.h> /* for aim_directim_initiate */#include <arpa/inet.h> /* for inet_ntoa */#endif/* TODO: o look for memory leaks.. there's going to be shitloads, i'm sure. */struct aim_directim_intdata { fu8_t cookie[8]; char sn[MAXSNLEN+1]; char ip[22];};static int listenestablish(fu16_t portnum); /** * aim_handlerendconnect - call this to accept OFT connections and set up the required structures * @sess: the session * @cur: the conn the incoming connection is on * * call this when you get an outstanding read on a conn with subtype * AIM_CONN_SUBTYPE_RENDEZVOUS_OUT, it will clone the current * &aim_conn_t and tweak things as appropriate. the new conn and the * listener conn are both returned to the client in the * %AIM_CB_FAM_OFT, %AIM_CB_OFT_<CLASS>INITIATE callback. */faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur){ int acceptfd = 0; struct sockaddr cliaddr; int clilen = sizeof(cliaddr); int ret = 0; aim_conn_t *newconn; if ((acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1) return 0; /* not an error */ if (cliaddr.sa_family != AF_INET) { /* just in case IPv6 really is happening */ close(acceptfd); aim_conn_close(cur); return -1; } if (!(newconn = aim_cloneconn(sess, cur))) { close(acceptfd); aim_conn_close(cur); return -1; } newconn->type = AIM_CONN_TYPE_RENDEZVOUS; newconn->fd = acceptfd; if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { struct aim_directim_intdata *priv; aim_rxcallback_t userfunc; priv = (struct aim_directim_intdata *)(newconn->internal = cur->internal); cur->internal = NULL; snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE))) ret = userfunc(sess, NULL, newconn, cur); } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {#if 0 struct aim_filetransfer_priv *priv; aim_rxcallback_t userfunc; newconn->priv = cur->priv; cur->priv = NULL; priv = (struct aim_filetransfer_priv *)newconn->priv; snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE))) ret = userfunc(sess, NULL, newconn, cur);#endif } else { faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous Closing conn.\n"); aim_conn_close(newconn); ret = -1; } return ret;}/** * aim_send_im_direct - send IM client-to-client over established connection * @sess: session to conn * @conn: directim connection * @msg: null-terminated string to send; if this is NULL, it will send a "typing" notice. * * Call this just like you would aim_send_im, to send a directim. You * _must_ have previously established the directim connection. */faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg){ struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; aim_frame_t *fr; aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */ if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, strlen(msg)))) return -ENOMEM; memcpy(fr->hdr.oft.magic, "ODC2", 4); fr->hdr.oft.hdr2len = 0x44; if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) { aim_frame_destroy(fr); return -ENOMEM; } aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); aimbs_put16(&hdrbs, 0x0006); aimbs_put16(&hdrbs, 0x0000); aimbs_putraw(&hdrbs, intdata->cookie, 8); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put32(&hdrbs, strlen(msg)); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); /* flags -- 0x000e for "typing", 0x0000 for message */ aimbs_put16(&hdrbs, msg ? 0x0000 : 0x000e); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_putraw(&hdrbs, sess->sn, strlen(sess->sn)); aim_bstream_setpos(&hdrbs, 52); /* bleeehh */ aimbs_put8(&hdrbs, 0x00); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); aimbs_put16(&hdrbs, 0x0000); /* end of hdr2 */ if (msg) {#if 0 /* XXX this is how you send buddy icon info... */ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008); i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c); i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466); i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001); i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f); i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e); i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);#endif aimbs_putraw(&fr->data, msg, strlen(msg)); } aim_tx_enqueue(sess, fr); return 0;} static int getlocalip(fu8_t *ip){ struct hostent *hptr; char localhost[129]; /* XXX if available, use getaddrinfo() */ /* XXX allow client to specify which IP to use for multihomed boxes */ if (gethostname(localhost, 128) < 0) return -1; if (!(hptr = gethostbyname(localhost))) return -1; memcpy(ip, hptr->h_addr_list[0], 4); return 0;}/** * aim_directim_intitiate - For those times when we want to open up the directim channel ourselves. * @sess: your session, * @conn: the BOS conn, * @priv: a dummy priv value (we'll let it get filled in later) (if you pass a %NULL, we alloc one) * @destsn: the SN to connect to. * */faim_export aim_conn_t *aim_directim_initiate(aim_session_t *sess, const char *destsn){ aim_conn_t *newconn; aim_msgcookie_t *cookie; struct aim_directim_intdata *priv; int listenfd; fu16_t port = 4443; fu8_t localip[4]; fu8_t ck[8]; if (getlocalip(localip) == -1) return NULL; if ((listenfd = listenestablish(port)) == -1) return NULL; aim_request_directim(sess, destsn, localip, port, ck); cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); memcpy(cookie->cookie, ck, 8); cookie->type = AIM_COOKIETYPE_OFTIM; /* this one is for the cookie */ priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); memcpy(priv->cookie, ck, 8); strncpy(priv->sn, destsn, sizeof(priv->sn)); cookie->data = priv; aim_cachecookie(sess, cookie); /* XXX switch to aim_cloneconn()? */ if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) { close(listenfd); return NULL; } /* this one is for the conn */ priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); memcpy(priv->cookie, ck, 8); strncpy(priv->sn, destsn, sizeof(priv->sn)); newconn->fd = listenfd; newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; newconn->internal = priv; newconn->lastactivity = time(NULL); faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); return newconn;}/** * aim_sendfile_intitiate - For those times when we want to send the file ourselves. * @sess: your session, * @conn: the BOS conn, * @destsn: the SN to connect to. * @filename: the name of the files you want to send * */faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *sess, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize){ aim_conn_t *newconn; aim_msgcookie_t *cookie; struct aim_directim_intdata *priv; int listenfd; fu16_t port = 4443; fu8_t localip[4]; fu8_t ck[8]; if (getlocalip(localip) == -1) return NULL; if ((listenfd = listenestablish(port)) == -1) return NULL; aim_request_sendfile(sess, destsn, filename, numfiles, totsize, localip, port, ck); cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); memcpy(cookie->cookie, ck, 8); cookie->type = AIM_COOKIETYPE_OFTIM; /* this one is for the cookie */ priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); memcpy(priv->cookie, ck, 8); strncpy(priv->sn, destsn, sizeof(priv->sn)); cookie->data = priv; aim_cachecookie(sess, cookie); /* XXX switch to aim_cloneconn()? */ if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) { close(listenfd); return NULL; } /* this one is for the conn */ priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); memcpy(priv->cookie, ck, 8); strncpy(priv->sn, destsn, sizeof(priv->sn)); newconn->fd = listenfd; newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; newconn->internal = priv; newconn->lastactivity = time(NULL); faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); return newconn;}#if 0/** * unsigned int aim_oft_listener_clean - close up old listeners * @sess: session to clean up in * @age: maximum age in seconds * * returns number closed, -1 on error. */faim_export unsigned int aim_oft_listener_clean(struct aim_session_t *sess, time_t age) { struct aim_conn_t *cur; time_t now; unsigned int hit = 0; if (!sess) return -1; now = time(NULL); faim_mutex_lock(&sess->connlistlock); for(cur = sess->connlist;cur; cur = cur->next) if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { faim_mutex_lock(&cur->active); if (cur->lastactivity < (now - age) ) { faim_mutex_unlock(&cur->active); aim_conn_close(cur); hit++; } else faim_mutex_unlock(&cur->active); } faim_mutex_unlock(&sess->connlistlock); return hit;} #endif faim_export const char *aim_directim_getsn(aim_conn_t *conn){ struct aim_directim_intdata *intdata; if (!conn) return NULL; if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) return NULL; if (!conn->internal) return NULL; intdata = (struct aim_directim_intdata *)conn->internal; return intdata->sn;}/** * aim_directim_connect - connect to buddy for directim * @sess: the session to append the conn to, * @sn: the SN we're connecting to * @addr: address to connect to * * This is a wrapper for aim_newconn. * * If addr is NULL, the socket is not created, but the connection is * allocated and setup to connect. * */faim_export aim_conn_t *aim_directim_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie){ aim_conn_t *newconn; struct aim_directim_intdata *intdata; if (!sess || !sn) return NULL; if (!(intdata = malloc(sizeof(struct aim_directim_intdata)))) return NULL; memset(intdata, 0, sizeof(struct aim_directim_intdata)); memcpy(intdata->cookie, cookie, 8); strncpy(intdata->sn, sn, sizeof(intdata->sn)); if (addr) strncpy(intdata->ip, addr, sizeof(intdata->ip)); /* XXX verify that non-blocking connects actually work */ if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { free(intdata); return NULL; } if (!newconn) { free(intdata); return newconn; } newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; newconn->internal = intdata; return newconn;} /** * aim_directim_getconn - find a directim conn for buddy name * @sess: your session, * @name: the name to get, * * returns conn for directim with name, %NULL if none found. * */faim_export aim_conn_t *aim_directim_getconn(aim_session_t *sess, const char *name){ aim_conn_t *cur; if (!sess || !name || !strlen(name)) return NULL; for (cur = sess->connlist; cur; cur = cur->next) { struct aim_directim_intdata *intdata; if ((cur->type != AIM_CONN_TYPE_RENDEZVOUS) || (cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) continue; intdata = cur->internal; if (aim_sncmp(intdata->sn, name) == 0) break; } return cur;} /** * aim_accepttransfer - accept a file transfer request * @sess: the session, * @conn: the BOS conn for the CAP reply * @sn: the screenname to send it to, * @cookie: the cookie used * @ip: the ip to connect to * @listingfiles: number of files to share * @listingtotsize: total size of shared files * @listingsize: length of the listing file(buffer) * @listingchecksum: checksum of the listing * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE) * * Returns new connection or %NULL on error. * * XXX this should take a struct. */faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t listingfiles, fu16_t listingtotsize,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -