📄 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 "IO.h"#include "Url.h"#include "../misc.h"#include "../../dpip/dpip.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; gint TokIdx; 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 *//* * Close a FD handling EINTR */static void Dpi_close_fd(gint fd){ gint st; do st = close(fd); while (st < 0 && errno == EINTR);}/* * 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->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, conn->BufSize + (gulong)io->Status); memcpy((gchar*)conn->Buf + conn->BufSize, io->Buf, (size_t)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 * * Return Value: 0 upon a new token, -1 on not enough data. * * TODO: define an API and move this function into libDpip.a.*/static gint Dpi_get_token(conn_data_t *conn){ gint i, 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->TokIdx = 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->TokIdx = 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 (EOT=" '>") */ for (i = conn->BufIdx; i < conn->BufSize; ++i) if (buf[i] == '>' && i >= 2 && buf[i-1] == '\'' && buf[i-2] == ' ') break; conn->BufIdx = i; if (conn->BufIdx < conn->BufSize) { /* found EOT */ conn->TokIsTag = 1; conn->TokSize = conn->BufIdx - conn->TokIdx + 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->Buf + conn->TokIdx, conn->TokSize, 0); a_Chain_fcb(OpSend, conn->InfoRecv, dbuf, "send_page_2eof"); g_free(dbuf); return; } tag = g_strndup(conn->Buf + conn->TokIdx, (guint)conn->TokSize); MSG("Dpi_parse_token: {%s}\n", tag); cmd = a_Dpip_get_attr(conn->Buf + conn->TokIdx, conn->TokSize, "cmd"); if (strcmp(cmd, "send_status_message") == 0) { msg = a_Dpip_get_attr(conn->Buf + conn->TokIdx, conn->TokSize, "msg"); a_Chain_fcb(OpSend, conn->InfoRecv, msg, cmd); g_free(msg); } else if (strcmp(cmd, "chat") == 0) { msg = a_Dpip_get_attr(conn->Buf + conn->TokIdx, conn->TokSize, "msg"); a_Chain_fcb(OpSend, conn->InfoRecv, msg, cmd); g_free(msg); } else if (strcmp(cmd, "dialog") == 0) { /* For now will send the dpip tag... */ a_Chain_fcb(OpSend, conn->InfoRecv, tag, cmd); } else if (strcmp(cmd, "start_send_page") == 0) { urlstr = a_Dpip_get_attr(conn->Buf + conn->TokIdx, conn->TokSize, "url"); a_Chain_fcb(OpSend, conn->InfoRecv, urlstr, cmd); g_free(urlstr); /* todo: a_Dpip_get_attr(conn->Buf + conn->TokIdx, * conn->TokSize, "send_mode") */ conn->Send2EOF = 1; } else if (strcmp(cmd, "reload_request") == 0) { urlstr = a_Dpip_get_attr(conn->Buf + conn->TokIdx, conn->TokSize, "url"); a_Chain_fcb(OpSend, conn->InfoRecv, urlstr, cmd); g_free(urlstr); } g_free(cmd); g_free(tag);}/* * 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(void){ 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"); Dpi_close_fd(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)); do n = write(st_pipe[1], "ERROR", 5); while (n == -1 && errno == EINTR); Dpi_close_fd(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)); /* close the unused pipe */ Dpi_close_fd(st_pipe[0]); Dpi_close_fd(st_pipe[1]); } else { /* This is the parent process, check our child status... */ Dpi_close_fd(st_pipe[1]); do n = read(st_pipe[0], buf, 16); while (n == -1 && errno == EINTR); 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. */static 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 { Dpi_close_fd(SockFD); ret = 0; } } return ret;}/* * Return the directory where the UDS are in, * NULL if it can't be found. */static gchar *Dpi_get_dpid_uds_dir(void){ FILE *in; gchar *saved_name_filename; /* :) */ gchar dpid_uds_dir[256], *p; saved_name_filename = g_strconcat(g_get_home_dir(), "/", ".dillo/dpi_socket_dir", NULL); in = fopen(saved_name_filename, "r"); g_free(saved_name_filename); if (in != NULL) { fgets(dpid_uds_dir, 256, in); fclose(in); if ((p = strchr(dpid_uds_dir, '\n'))) *p = 0; if (access(dpid_uds_dir, F_OK) == 0) p = g_strdup(dpid_uds_dir); _MSG("Dpi_get_dpid_uds_dir:: %s\n", p); return p; } _MSG("Dpi_get_dpid_uds_dir: %s \n", g_strerror(errno)); return NULL;}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -