📄 dpi.c
字号:
/* * File: dpi.c * * Copyright (C) 2002, 2003 Jorge Arellano Cid <jcid@dillo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * (Prototype code) * * Dillo plugins (small programs that interact with dillo) * This should be able to handle: * bookmarks, cookies, FTP, downloads, preferences, https and * a lot of any-to-html filters. */#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#include <stdio.h>#include <errno.h> /* for errno */#include <stdio.h>#include <sys/socket.h>#include <sys/un.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include "../msg.h"#include "Url.h"#include "IO.h"#include "../misc.h"//#define DEBUG_LEVEL 2#define DEBUG_LEVEL 4#include "../debug.h"/* This one is tricky, some sources state it should include the byte * for the terminating NULL, and others say it shouldn't. */# define D_SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ + strlen ((ptr)->sun_path))/* Solaris may not have this one... */#ifndef AF_LOCAL#define AF_LOCAL AF_UNIX#endiftypedef struct { gint FreeBuf; gint InTag, InData; gint PipeActive; gint Send2EOF; gint DataTotalSize; gint DataRecvSize; void *Buf; gint BufIdx; gint BufSize; gchar *Tok; gint TokSize; gint TokIsTag; ChainLink *InfoRecv;} conn_data_t;/* * Local data *//* list for dpi connections waiting for a FD; * it holds pointers to Info structures (i.e. CCC Nodes). */static GSList *PendingNodes = NULL;/* * Forward references *//* * Task: given a tag and an attribute name, return its value. * (character stuffing is removed here) * Return value: the attribute value, or NULL if not present or malformed. */char *Get_attr_value(char *tag, int tagsize, char *attrname){ char *p, *q, *ltag, quote, *start, *val = NULL; ltag = g_strndup(tag, tagsize); if ((p = strstr(ltag, attrname)) && (p = strchr(p, '=')) && (p = strpbrk(p, "'\"")) ) { quote = *p; start = ++p; while ((q = strchr(p, quote)) && q[1] == quote) p = q + 2; if (q) { val = g_strndup(start, q - start); for (p = q = val; (*q = *p); ++p, ++q) if ((*p == '"' || *p == '\'') && p[1] == p[0]) ++p; } } g_free(ltag); return val;}/* * Create a new connection data structure */static conn_data_t *Dpi_conn_data_new(ChainLink *Info){ conn_data_t *conn = g_new0(conn_data_t, 1); conn->Buf = NULL; conn->Tok = NULL; conn->InfoRecv = Info; return conn;}/* * Free a connection data structure */static void Dpi_conn_data_free(conn_data_t *conn){ if (conn->FreeBuf) g_free(conn->Buf); g_free(conn);}/* * Append the new buffer in 'io' to Buf in 'conn' */static void Dpi_append_io_buf(conn_data_t *conn, IOData_t *io){ if (io->Status > 0) { conn->Buf = g_realloc(conn->Buf, io->Status); memcpy(conn->Buf + conn->BufSize, io->Buf, io->Status); conn->BufSize += io->Status; conn->FreeBuf = 0; }}/* * Split the data stream into tokens. * Here, a token is either: * a) a dpi tag * b) a raw data chunk */static gint Dpi_get_token(conn_data_t *conn){ gint resp = -1; gchar *buf = conn->Buf; if (conn->FreeBuf || conn->BufIdx == conn->BufSize) { g_free(conn->Buf); conn->Buf = NULL; conn->BufIdx = conn->BufSize = 0; conn->FreeBuf = 0; return resp; } if (conn->Send2EOF) { conn->Tok = buf + conn->BufIdx; conn->TokSize = conn->BufSize - conn->BufIdx; conn->BufIdx = conn->BufSize; return 0; } if (!conn->InTag && !conn->InData) { /* search for start of tag *//*gchar *pbuf=NULL;MSG("conn->BufIdx = %d; conn->BufSize = %d\n", conn->BufIdx,conn->BufSize);pbuf = g_strndup(buf, conn->BufSize - conn->BufIdx);MSG("buf: [%s]\n", pbuf);g_free(pbuf);*/ while (conn->BufIdx < conn->BufSize && buf[conn->BufIdx] != '<') ++conn->BufIdx; if (conn->BufIdx < conn->BufSize) { /* found */ conn->InTag = 1; conn->Tok = buf + conn->BufIdx; } else { MSG("ERROR: [Dpi_get_token] Can't find token start\n"); conn->FreeBuf = 1; return Dpi_get_token(conn); } } if (conn->InTag) { /* search for end of tag */ while (conn->BufIdx < conn->BufSize && buf[conn->BufIdx] != '>') ++conn->BufIdx; if (conn->BufIdx < conn->BufSize) { /* found EOT */ conn->TokIsTag = 1; conn->TokSize = buf + conn->BufIdx - conn->Tok + 1; ++conn->BufIdx; conn->InTag = 0; resp = 0; } } if (conn->InData) { conn->TokIsTag = 0; if (conn->DataRecvSize + conn->BufSize - conn->BufIdx < conn-> DataTotalSize) { conn->TokSize += conn->BufSize - conn->BufIdx; conn->DataRecvSize += conn->BufSize - conn->BufIdx; conn->FreeBuf = 1; resp = 0; } else { /* srch end of data */ MSG("ERROR: [Dpi_get_token] *** NULL code here ***\n"); while (conn->BufIdx < conn->BufSize) ++conn->BufIdx; resp = -1; } } return resp;}/* * Parse a dpi tag and take the appropriate actions */static void Dpi_parse_token(conn_data_t *conn){ gchar *tag, *cmd, *msg, *urlstr; DataBuf *dbuf; if (conn->Send2EOF) { /* we're receiving data chunks from a HTML page */ dbuf = a_Chain_dbuf_new(conn->Tok, conn->TokSize, 0); a_Chain_fcb(OpSend, conn->InfoRecv, dbuf, "send_page_2eof"); g_free(dbuf); return; } tag = g_strndup(conn->Tok, conn->TokSize); MSG("Dpi_parse_token: [%s]\n", tag); g_free(tag); cmd = Get_attr_value(conn->Tok, conn->TokSize, "cmd"); if (strcmp(cmd, "send_status_message") == 0) { msg = Get_attr_value(conn->Tok, conn->TokSize, "msg"); a_Chain_fcb(OpSend, conn->InfoRecv, msg, cmd); g_free(msg); } else if (strcmp(cmd, "chat") == 0) { msg = Get_attr_value(conn->Tok, conn->TokSize, "msg"); a_Chain_fcb(OpSend, conn->InfoRecv, msg, cmd); g_free(msg); } else if (strcmp(cmd, "start_send_page") == 0) { urlstr = Get_attr_value(conn->Tok, conn->TokSize, "url"); a_Chain_fcb(OpSend, conn->InfoRecv, urlstr, cmd); g_free(urlstr); /* todo: Get_attr_value(conn->Tok, conn->TokSize, "send_mode") */ conn->Send2EOF = 1; } else if (strcmp(cmd, "reload_request") == 0) { urlstr = Get_attr_value(conn->Tok, conn->TokSize, "url"); a_Chain_fcb(OpSend, conn->InfoRecv, urlstr, cmd); g_free(urlstr); } g_free(cmd);}/* * Compare function for searching a CCC Node with a 'web' pointer. */static gint Dpi_node_cmp(gconstpointer node, gconstpointer key){ return a_Url_cmp(key, ((ChainLink *)node)->LocalKey);}/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *//* * Get a new data buffer (within an 'io'), save it into local data, * split in tokens and parse the contents. */static void Dpi_process_io(int Op, void *Data1, conn_data_t *conn){ IOData_t *io = Data1; /* Very useful for debugging: show the data stream as received. */ // fwrite(io->Buf, io->Status, 1, stdout); if (Op == IORead) { Dpi_append_io_buf(conn, io); while (Dpi_get_token(conn) != -1) { Dpi_parse_token(conn); } } else if (Op == IOClose) { MSG("Dpi: [Dpi_process_io] IOClose\n"); }}/* * Start dpid. * Return: 0 starting now, 1 Error. */static gint Dpi_start_dpid(){ pid_t pid; gint st_pipe[2], n, ret = 1; gchar buf[16]; /* create a pipe to track our child's status */ if (pipe(st_pipe)) return 1; pid = fork(); if (pid == 0) { /* This is the child process. Execute the command. */ gchar *path1 = a_Misc_prepend_user_home(".dillo/dpid"); close(st_pipe[0]); if (execl(path1, "dpid", NULL) == -1) { g_free(path1); if (execlp("dpid", "dpid", NULL) == -1) { DEBUG_MSG(4, "Dpi_start_dpid (child): %s\n", g_strerror(errno)); write(st_pipe[1], "ERROR", 5); close(st_pipe[1]); _exit (EXIT_FAILURE); } } } else if (pid < 0) { /* The fork failed. Report failure. */ DEBUG_MSG(4, "Dpi_start_dpid: %s\n", g_strerror(errno)); } else { /* This is the parent process, check our child status... */ close(st_pipe[1]); n = read(st_pipe[0], buf, 16); DEBUG_MSG(2, "Dpi_start_dpid: n = %d\n", n); if (n != 5) ret = 0; else DEBUG_MSG(4, "Dpi_start_dpid: %s\n", g_strerror(errno)); } return ret;}/* * Make a connection test for a UDS. * Return: 0 OK, 1 Not working. */gint Dpi_check_uds(gchar *uds_name){ struct sockaddr_un pun; gint SockFD, ret = 1; if (access(uds_name, W_OK) == 0) { /* socket connection test */ memset(&pun, 0, sizeof(struct sockaddr_un)); pun.sun_family = AF_LOCAL; strncpy(pun.sun_path, uds_name, sizeof (pun.sun_path)); if ((SockFD = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1 || connect(SockFD, (void*)&pun, D_SUN_LEN(&pun)) == -1) { DEBUG_MSG(4, "Dpi_check_uds: %s %s\n", g_strerror(errno), uds_name); } else { close(SockFD); ret = 0; } } return ret;}/* * Return the directory where the UDS are in, * NULL if it can't be found. */gchar *Dpi_get_dpid_uds_dir(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -