2007年11月4日星期日

一个测试procmailrc的脚本

在你的测试目录(/home/myid/test,可以改)下建proctest.rc作为procmailrc文件,邮件文件为mail.msg(只包含一个邮件),直接运行proctest就可以了
 
#!/bin/sh
#The executable file named "proctest"
#
# You need a test directory.
TESTDIR=/home/myid/test
if [ ! -d ${TESTDIR} ] ; then
  echo "Directory ${TESTDIR} does not exist; First create it"
  exit 0
fi
#
#Feed an email message to procmail. Apply proctest.rc recipes file.
#First prepare a mail.msg email file which you wish to use for the
#testing.
procmail ${TESTDIR}/proctest.rc < mail.msg
#
#Show the results.
less ${TESTDIR}/Proctest.log
clear
less ${TESTDIR}/Proctest.mail
#
#Clean up.
rm -i ${TESTDIR}/Proctest.log
rm -i ${TESTDIR}/Proctest.mail
 
下面是一个简单的procmailrc的例子proctest.rc
 
SHELL=/bin/sh TESTDIR=/home/myid/test MAILDIR=${TESTDIR} LOGFILE=${TESTDIR}/Proctest.log LOG="--- Logging for ${LOGNAME}, "  #Troubleshooting: VERBOSE=yes LOGABSTRACT=all  #Let's test stripping lines from the email message's header :0 fwh | egrep -vi "(^Content-|^MIME-Version:.)"  #If it is from myself, store the email message :0: * $ ^From:.*${LOGNAME} ${TESTDIR}/Proctest.mail  #Otherwise, discard the email message :0 /dev/null 


--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

procmailrc examples

 
email MIME/QP decode
取名� /etc/parser_subj   (mode 755)

#!/usr/bin/perl
    $sub=join(" ",@ARGV);
    if ($sub=~ /=\?\S+\?\l(\S)\?/) {
      if ($1 =~ /[Qq]/) {
        $sub=decode_qp($sub);
      }
      elsif ($1 =~ /[Bb]/) {
        $sub=decode_base64($sub);
      }
    }
    elsif ($sub=~ /=[a-fA-F0-9][a-fA-F0-9]/) {
      $sub=decode_qp($sub);
    }
    $subject.=$sub;
    $subject=~s/\'/\\\'/g;
    $subject=~s/\"/\\\"/g;
print $subject;
sub decode_qp {
        my($string) = @_;
        @buffer=split(/\?/,$string);
        $string = $buffer[3] if ($buffer[3] ne "");
        $string =~ s/=([\da-fA-F]{2})/pack("C", hex($1))/ge;
        $string =~ /\?=(.*)/;
        $string =~ tr/_/ /;
        $buffer[4]=~s/^=//;
        $buffer[0]=~s/=$//;
        $string="$buffer[0]$string$buffer[4]";
        return($string);
}

sub decode_base64 {
        my($string) = @_;
        my($string2);
        @buffer=split(/\?/,$string);
        $string = $buffer[3] if ($buffer[3] ne "");
        $string =~ s/=+$//;
        $string =~ tr|A-Za-z0-9+/| -_|;
        while($string =~ /(.{1,60})/gs) {
                my($string3) = chr(32+length($1)*3/4);
                $string2 .= unpack("u",$string3 . $1 );
        }
        $buffer[4]=~s/^=//;
        $buffer[0]=~s/=$//;
        $string2="$buffer[0]$string2$buffer[4]";
        return($string2);
}



在 procmail 中加入:

LOGABSTRACT=all
LOGFILE=/tmp/procmail.log
tmp=`formail -I "" | sed -e '/Content-Type/,/^$/!d' | grep "filename=" | sed -e 's/.*filename\=\(.*\)\?.*/\1/g'`
ATTACH=`/etc/parser_subj $tmp`

:0
....��你自己去�吧...自己做�功�就�了


去看 /tmp/procmail.log 中的�西,就知道用意了
PATH=$PATH
SHELL=/bin/sh
MAILDIR=/var/spool/mail
VERBOSE=yes
LOGABSTRACT=all
SENDMAIL=/usr/sbin/sendmail
LOGFILE=$HOME/procmail/procmail.log
FILE=`echo $HOME`/procmail/mail_folder/mail-`date +%Y%m%d%H%I%S`-`echo $$`.eml
tmp=`formail >; $FILE; chmod 644 $FILE`
tmp=`formail -zxSubject:`
SUBJ=`/etc/parser_subj "$tmp"| sed -e "s/[\$,\(,\),\',\\]//g"`
FROM=`formail -zxFrom:| sed -e 's/.*<\(.*\)>;.*/\1/g'`
SPAMID=`formail -I ""|grep '/sc?id=' | sed -e 's/.*id=\(.*\)/\1/g'`
PTR=`formail -zxReceived:|grep ^from|sed -e 's/.*\[\(.*\)\.\(.*\)\.\(.*\)\.\(.*\)\].*/\4.\3.\2.\1/g'|head -1`
MYSQL="mysql -h procmail.mydomain.net.tw -u abel -pxxxxxxxx procmail"

# ���取回�的信不再��
:0 H
* ^X-resend:
/var/spool/mail/$LOGNAME


# 白名��理
WHITE_LIST=`echo "SELECT WHITE_NAME FROM WHITE_LIST WHERE USERNAME='$LOGNAME' AND instr('$FROM', WHITE_NAME ) or instr('$SUBJ', WHITE_NAME )"| $MYSQL |  tr '\n' '|' ; echo "aaaaaaaazzzzzzzzzggggggggg"`

:0 H

* $($WHITE_LIST)

$ORGMAIL



# �?#125;中巳�有 SPAM

:0 HD

* ^Subject: SPAM.*

{

        :0 fw

        | ( echo "insert into SPAM(MAIL_FROM,RCPT_TO,SUBJ,FILE_NAME,MAIL_TYPE,USERNAME,REASON,PATTEN ) values('$FROM ','$TO ','$SUBJ ','$FILE',1,'$LOGNAME','SPAM','�?#125; SPAM')"    | $MYSQL)



        :0

        /dev/null

}



# �信不�自己�位但  Message-ID �自己

:0 HD

* !^From: .*@mydomain.net.tw.*

* !^Received: .*211\.72\.21[0-1]\..*

* ^Message-Id: .*@mydomain.net.*

{

:0 fw

| echo "insert into SPAM(MAIL_FROM,RCPT_TO,SUBJ,FILE_NAME,MAIL_TYPE,USERNAME,REASON,PATTEN ) values('$FROM ','$TO ','$SUBJ ','$FILE',1,'$LOGNAME','�信��','Message-ID � mydomain')"    | $MYSQL



:0

/dev/null

}



# spamcop 的��信回函�存 mysql, 再以程式去 submit form

:0 H

* ^Subject: .*SpamCop has accepted.*

{

        :0 fw

        | ( echo "insert into SPAMCOP_ID(SPAM_ID) values('$SPAMID')" | $MYSQL)



        :0

        /dev/null

}



# 一些大的�告信商

:0 HD

* (^From:|^Received:|Return-Path:) .*(mailserver.idv.tw|mailserver.com|worldad.net|mailnews.com.tw|rayman.com.cn).*

{

:0 fw

| echo "insert into SPAM(MAIL_FROM,RCPT_TO,SUBJ,FILE_NAME,MAIL_TYPE,USERNAME,REASON,PATTEN ) values('$FROM ','$TO ','$SUBJ ','$FILE',1,'$LOGNAME','�信��','mailserver 信商�出')"    | $MYSQL



:0

/dev/null

}





# 收信人��字型�

:0 HD

* ^To: .*[0-9][0-9].txt.*

{

:0 fw

| echo "insert into SPAM(MAIL_FROM,RCPT_TO,SUBJ,FILE_NAME,MAIL_TYPE,USERNAME,REASON,PATTEN ) values('$FROM ','$TO ','$SUBJ ','$FILE',1,'$LOGNAME','�信��','�字型收件者')"    | $MYSQL



:0

/dev/null

}



# From: user@mydomain.net.tw 但不�自己人

:0 HD

* ^From: .*@mydomain.net.tw.*

* !^Received: .*211\.72\.21[0-1]\..*

{

:0 fw

| (username=${FROM%%@*};if [ -d /home/$username ] ; then formail -A "Bogus: No"; else formail -A "Bogus: Yes";  echo "insert into SPAM(MAIL_FROM,RCPT_TO,SUBJ,FILE_NAME,MAIL_TYPE,USERNAME,REASON,PATTEN ) values('$FROM ','$TO ','$SUBJ ','$FILE',1,'$LOGNAME','寄件人不存在','$FROM ')" | $MYSQL ;fi  );



:0 

* ^Bogus: Yes

/dev/null

}





# 主旨��,�料存?mysql

:0 HD

* ! ^From: .*@mydomain.net.tw.*

{

patten=`echo "select concat(\"'\",PATTEN,\"'\") from SPAM_PATTEN where USERNAME='$LOGNAME' and instr('$SUBJ',PATTEN)"|$MYSQL | grep -v 'PATTEN'| tr '\n' ','`

patten2=`echo $patten | sed -e "s/'//g"`



        :0 fw

* ? test -n "$patten"

        | ( formail -A "Spam: $patten" ; \

echo "insert into SPAM(MAIL_FROM,RCPT_TO,SUBJ,FILE_NAME,MAIL_TYPE,USERNAME,REASON,PATTEN ) values('$FROM ','$TO ','$SUBJ ','$FILE',1,'$LOGNAME','符合特定字串','$patten2'); update SPAM_PATTEN set CNT=CNT+1 where USERNAME='$LOGNAME' and PATTEN in ($patten ''); " | $MYSQL ;\

)



        :0

        * ^Spam: .*

        /dev/null

}



# RBL ��, rbl doamin 存於 mysql

:0 

* ! ^From: .*@(mydomain.net.tw|mydomain.net).*

* ! ^Received: .*159\.226\.*

{

rbl=`for spam in $(echo "select RBL_DOMAIN from SPAM_SOURCE order by SN"| $MYSQL | grep -v 'RBL_DOMAIN'); do  rbl=$(host $PTR.$spam| grep 'has address'); test -n "$rbl" && echo $PTR.$spam && break; done`



        :0 fw

|( test -n "$rbl" && (echo "insert into SPAM(MAIL_FROM,RCPT_TO,SUBJ,FILE_NAME,MAIL_TYPE,USERNAME,REASON,PATTEN ) values('$FROM ','$TO ','$SUBJ ','$FILE',1,'$LOGNAME','�自 RBL IP','$rbl.$spam')" | $MYSQL) && formail -A "Spam: From_RBL $rbl.$spam" )



        :0

        * ^Spam: .*

        /dev/null

}
�果呈�:
http://211.72.210.251/spamcop.html
 
2007-11-04

r01ustc

2007年11月3日星期六

使用 OpenSSL API 进行安全编程


OpenSSL API 的文档有些含糊不清。因为还没有多少关于 OpenSSL 使用的教程,所以对初学者来说,在应用程序中使用它可能会有一些困难。那么怎样才能使用 OpenSSL 实现一个基本的安全连接呢?本教程将帮助您解决这个问题。

学习如何实现 OpenSSL 的困难部分在于其文档的不完全。不完全的 API 文档通常会妨碍开发人员使用该 API,而这通常意味着它注定要失败。但 OpenSSL 仍然很活跃,而且正逐渐变得强大。这是为什么?

OpenSSL 是用于安全通信的最著名的开放库。在 google 中搜索"SSL library"得到的返回结果中,列表最上方就是 OpenSSL。它诞生于 1998 年,源自 Eric Young 和 Tim Hudson 开发的 SSLeay 库。其他 SSL 工具包包括遵循 GNU General Public License 发行的 GNU TLS,以及 Mozilla Network Security Services(NSS)(请参阅本文后面的 参考资料 ,以获得其他信息)。

那么,是什么使得 OpenSSL 比 GNU TLS、Mozilla NSS 或其他所有的库都优越呢?许可是一方面因素(请参阅 参考资料)。此外,GNS TLS(迄今为止)只支持 TLS v1.0 和 SSL v3.0 协议,仅此而已。

Mozilla NSS 的发行既遵循 Mozilla Public License 又遵循 GNU GPL,它允许开发人员进行选择。不过,Mozilla NSS 比 OpenSSL 大,并且需要其他外部库来对库进行编译,而 OpenSSL 是完全自包含的。与 OpenSSL 相同,大部分 NSS API 也没有文档资料。Mozilla NSS 获得了 PKCS #11 支持,该支持可以用于诸如智能卡这样的加密标志。OpenSSL 就不具备这一支持。

先决条件

要充分理解并利用本文,您应该:

  • 精通 C 编程。
  • 熟悉 Internet 通信和支持 Internet 的应用程序的编写。

并不绝对要求您熟悉 SSL ,因为稍后将给出对 SLL 的简短说明;不过,如果您希望得到详细论述 SSL 的文章的链接,请参阅 参考资料部分。拥有密码学方面的知识固然好,但这并不是必需的。





回页首


什么是 SSL?

SSL 是一个缩写,代表的是 Secure Sockets Layer。它是支持在 Internet 上进行安全通信的标准,并且将数据密码术集成到了协议之中。数据在离开您的计算机之前就已经被加密,然后只有到达它预定的目标后才被解密。证书和密码学算法支持了这一切的运转,使用 OpenSSL,您将有机会切身体会它们。

理论上,如果加密的数据在到达目标之前被截取或窃听,那些数据是不可能被破解的。不过,由于计算机的变化一年比一年快,而且密码翻译方法有了新的发展,因此,SSL 中使用的加密协议被破解的可能性也在增大。

可以将 SSL 和安全连接用于 Internet 上任何类型的协议,不管是 HTTP、POP3,还是 FTP。还可以用 SSL 来保护 Telnet 会话。虽然可以用 SSL 保护任何连接,但是不必对每一类连接都使用 SSL。如果连接传输敏感信息,则应使用 SSL。





回页首


什么是 OpenSSL?

OpenSSL 不仅仅是 SSL。它可以实现消息摘要、文件的加密和解密、数字证书、数字签名和随机数字。关于 OpenSSL 库的内容非常多,远不是一篇文章可以容纳的。

OpenSSL 不只是 API,它还是一个命令行工具。命令行工具可以完成与 API 同样的工作,而且更进一步,可以测试 SSL 服务器和客户机。它还让开发人员对 OpenSSL 的能力有一个认识。要获得关于如何使用 OpenSSL 命令行工具的资料,请参阅 参考资料部分。





回页首


您需要什么

首先需要的是最新版本的 OpenSSL。查阅参考资料部分,以确定从哪里可以获得最新的可以自己编译的源代码,或者最新版本的二进制文件(如果您不希望花费时间来编译的话)。不过,为了安全起见,我建议您下载最新的源代码并自己编译它。二进制版本通常是由第三方而不是由 OpenSSL 的开发人员来编译和发行的。

一些 Linux 的发行版本附带了 OpenSSL 的二进制版本,对于学习如何使用 OpenSSL 库来说,这足够了;不过,如果您打算去做一些实际的事情,那么一定要得到最新的版本,并保持该版本一直是最新的。

对于以 RPM 形式安装的 Linux 发行版本(Red Hat、Mandrake 等),建议您通过从发行版本制造商那里获得 RPM 程序包来更新您的 OpenSSL 发行版本。出于安全方面的原因,建议您使用最新版本的发行版本。如果您的发行版本不能使用最新版本的 OpenSSL,那么建议您只覆盖库文件,不要覆盖可执行文件。OpenSSL 附带的 FAQ 文档中包含了有关这方面的细节。

还要注意的是,OpenSSL 并没有在所有的平台上都获得官方支持。虽然制造商已经尽力使其能够跨平台兼容,但仍然存在 OpenSSL 不能用于您的计算机 和/或 操作系统的可能。请参阅 OpenSSL 的 Web 站点( 参考资料 中的链接),以获得关于哪些平台可以得到支持的信息。

如果想使用 OpenSSL 来生成证书请求和数字证书,那么必须创建一个配置文件。在 OpenSSL 程序包的 apps 文件夹中,有一个名为 openssl.cnf 的可用模板文件。我不会对该文件进行讨论,因为这不在本文要求范围之内。不过,该模板文件有一些非常好的注释,而且如果在 Internet 上搜索,您可以找到很多讨论修改该文件的教程。





回页首


头文件和初始化

本教程所使用的头文件只有三个:ssl.h、bio.h 和 err.h。它们都位于 openssl 子目录中,而且都是开发您的项目所必需的。要初始化 OpenSSL 库,只需要三个代码行即可。清单 1 中列出了所有内容。其他的头文件 和/或 初始化函数可能是其他一些功能所必需的。


清单 1. 必需的头文件
/* OpenSSL headers */  #include "openssl/bio.h"  #include "openssl/ssl.h"  #include "openssl/err.h"  /* Initializing OpenSSL */  SSL_load_error_strings();  ERR_load_BIO_strings();  OpenSSL_add_all_algorithms();  





回页首


建立非安全连接

不管连接是安全的还是不安全的,OpenSSL 都使用了一个名为 BIO 的抽象库来处理包括文件和套接字在内的各种类型的通信。您还可以将 OpenSSL 设置成为一个过滤器,比如用于 UU 或 Base64 编码的过滤器。

在这里对 BIO 库进行全面说明有点麻烦,所以我将根据需要一点一点地介绍它。首先,我将向您展示如何建立一个标准的套接字连接。相对于使用 BSD 套接字库,该操作需要的代码行更少一些。

在建立连接(无论安全与否)之前,要创建一个指向 BIO 对象的指针。这类似于在标准 C 中为文件流创建 FILE 指针。


清单 2. 指针
BIO * bio;  

打开连接

创建新的连接需要调用 BIO_new_connect 。您可以在同一个调用中同时指定主机名和端口号。也可以将其拆分为两个单独的调用:一个是创建连接并设置主机名的 BIO_new_connect 调用,另一个是设置端口号的 BIO_set_conn_port (或者 BIO_set_conn_int_port )调用。

不管怎样,一旦 BIO 的主机名和端口号都已指定,该指针会尝试打开连接。没有什么可以影响它。如果创建 BIO 对象时遇到问题,指针将会是 NULL。为了确保连接成功,必须执行 BIO_do_connect 调用。


清单 3. 创建并打开连接
bio = BIO_new_connect("hostname:port");  if(bio == NULL)  {      /* Handle the failure */  }  if(BIO_do_connect(bio) <= 0)  {      /* Handle failed connection */  }  

在这里,第一行代码使用指定的主机名和端口创建了一个新的 BIO 对象,并以所示风格对该对象进行 格式化。例如,如果您要连接到 www.ibm.com 的 80 端口,那么该字符串将是 www.ibm.com:80 。调用 BIO_do_connect 检查连接是否成功。如果出错,则返回 0 或 -1。

与服务器进行通信

不管 BIO 对象是套接字还是文件,对其进行的读和写操作都是通过以下两个函数来完成的: BIO_readBIO_write 。很简单,对吧?精彩之处就在于它始终如此。

BIO_read 将尝试从服务器读取一定数目的字节。它返回读取的字节数、 0 或者 -1。在受阻塞的连接中,该函数返回 0,表示连接已经关闭,而 -1 则表示连接出现错误。在非阻塞连接的情况下,返回 0 表示没有可以获得的数据,返回 -1 表示连接出错。可以调用 BIO_should_retry 来确定是否可能重复出现该错误。


清单 4. 从连接读取
int x = BIO_read(bio, buf, len);  if(x == 0)  {      /* Handle closed connection */  }  else if(x < 0)  {     if(! BIO_should_retry(bio))      {          /* Handle failed read here */      }      /* Do something to handle the retry */  }  

BIO_write 会试着将字节写入套接字。它将返回实际写入的字节数、0 或者 -1。同 BIO_read ,0 或 -1 不一定表示错误。 BIO_should_retry 是找出问题的途径。如果需要重试写操作,它必须使用和前一次完全相同的参数。


清单 5. 写入到连接
if(BIO_write(bio, buf, len) <= 0)  {      if(! BIO_should_retry(bio))      {          /* Handle failed write here */      }      /* Do something to handle the retry */  }  

关闭连接

关闭连接也很简单。您可以使用以下两种方式之一来关闭连接: BIO_resetBIO_free_all 。如果您还需要重新使用对象,那么请使用第一种方式。如果您不再重新使用它,则可以使用第二种方式。

BIO_reset 关闭连接并重新设置 BIO 对象的内部状态,以便可以重新使用连接。如果要在整个应用程序中使用同一对象,比如使用一台安全的聊天客户机,那么这样做是有益的。该函数没有返回值。

BIO_free_all 所做正如其所言:它释放内部结构体,并释放所有相关联的内存,其中包括关闭相关联的套接字。如果将 BIO 嵌入于一个类中,那么应该在类的析构函数中使用这个调用。


清单 6. 关闭连接
/* To reuse the connection, use this line */  BIO_reset(bio);  /* To free it from memory, use this line */  BIO_free_all(bio);  





回页首


建立安全连接

现在需要给出建立安全连接需要做哪些事情。惟一要改变的地方就是建立并进行连接。其他所有内容都是相同的。

安全连接要求在连接建立后进行握手。在握手过程中,服务器向客户机发送一个证书,然后,客户机根据一组可信任证书来核实该证书。它还将检查证书,以确保它没有过期。要检验证书是可信任的,需要在连接建立之前提前加载一个可信任证书库。

只有在服务器发出请求时,客户机才会向服务器发送一个证书。该过程叫做客户机认证。使用证书,在客户机和服务器之间传递密码参数,以建立安全连接。尽管握手是在建立连接之后才进行的,但是客户机或服务器可以在任何时刻请求进行一次新的握手。

参考资料 部分中列出的 Netscasp 文章和 RFC 2246 ,对握手以及建立安全连接的其他方面的知识进行了更详尽的论述。

为安全连接进行设置

为安全连接进行设置要多几行代码。同时需要有另一个类型为 SSL_CTX 的指针。该结构保存了一些 SSL 信息。您也可以利用它通过 BIO 库建立 SSL 连接。可以通过使用 SSL 方法函数调用 SSL_CTX_new 来创建这个结构,该方法函数通常是 SSLv23_client_method

还需要另一个 SSL 类型的指针来保持 SSL 连接结构(这是短时间就能完成的一些连接所必需的)。以后还可以用该 SSL 指针来检查连接信息或设置其他 SSL 参数。


清单 7. 设置 SSL 指针
SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());  SSL * ssl;  

加载可信任证书库

在创建上下文结构之后,必须加载一个可信任证书库。这是成功验证每个证书所必需的。如果不能确认证书是可信任的,那么 OpenSSL 会将证书标记为无效(但连接仍可以继续)。

OpenSSL 附带了一组可信任证书。它们位于源文件树的 certs 目录中。不过,每个证书都是一个独立的文件 �� 也就是说,需要单独加载每一个证书。在 certs 目录下,还有一个存放过期证书的子目录。试图加载这些证书将会出错。

如果您愿意,可以分别加载每一个文件,但为了简便起见,最新的 OpenSSL 发行版本的可信任证书通常存放在源代码档案文件中,这些档案文件位于名为"TrustStore.pem"的单个文件中。如果已经有了一个可信任证书库,并打算将它用于特定的项目中,那么只需使用您的文件替换清单 8 中的"TrustStore.pem"(或者使用单独的函数调用将它们全部加载)即可。

可以调用 SSL_CTX_load_verify_locations 来加载可信任证书库文件。这里要用到三个参数:上下文指针、可信任库文件的路径和文件名,以及证书所在目录的路径。必须指定可信任库文件或证书的目录。如果指定成功,则返回 1,如果遇到问题,则返回 0。


清单 8. 加载信任库
if(! SSL_CTX_load_verify_locations(ctx, "/path/to/TrustStore.pem", NULL))  {      /* Handle failed load here */  }  

如果打算使用目录存储可信任库,那么必须要以特定的方式命名文件。OpenSSL 文档清楚地说明了应该如何去做,不过,OpenSSL 附带了一个名为 c_rehash 的工具,它可以将文件夹配置为可用于 SSL_CTX_load_verify_locations 的路径参数。


清单 9. 配置证书文件夹并使用它
/* Use this at the command line */  c_rehash /path/to/certfolder  /* then call this from within the application */  if(! SSL_CTX_load_verify_locations(ctx, NULL, "/path/to/certfolder"))  {      /* Handle error here */  }  

为了指定所有需要的验证证书,您可以根据需要命名任意数量的单独文件或文件夹。您还可以同时指定文件和文件夹。

创建连接

将指向 SSL 上下文的指针作为惟一参数,使用 BIO_new_ssl_connect 创建 BIO 对象。还需要获得指向 SSL 结构的指针。在本文中,只将该指针用于 SSL_set_mode 函数。而这个函数是用来设置 SSL_MODE_AUTO_RETRY 标记的。使用这个选项进行设置,如果服务器突然希望进行一次新的握手,那么 OpenSSL 可以在后台处理它。如果没有这个选项,当服务器希望进行一次新的握手时,进行读或写操作都将返回一个错误,同时还会在该过程中设置 retry 标记。


清单 10. 设置 BIO 对象
bio = BIO_new_ssl_connect(ctx);  BIO_get_ssl(bio, & ssl);  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);  

设置 SSL 上下文结构之后,就可以创建连接了。主机名是使用 BIO_set_conn_hostname 函数设置的。主机名和端口的指定格式与前面的相同。该函数还可以打开到主机的连接。为了确认已经成功打开连接,必须执行对 BIO_do_connect 的调用。该调用还将执行握手来建立安全连接。


清单 11. 打开安全连接
/* Attempt to connect */  BIO_set_conn_hostname(bio, "hostname:port");  /* Verify the connection opened and perform the handshake */  if(BIO_do_connect(bio) <= 0)  {      /* Handle failed connection */  }  

连接建立后,必须检查证书,以确定它是否有效。实际上,OpenSSL 为我们完成了这项任务。如果证书有致命的问题(例如,哈希值无效),那么将无法建立连接。但是,如果证书的问题并不是致命的(当它已经过期或者尚不合法时),那么仍可以继续使用连接。

可以将 SSL 结构作为惟一参数,调用 SSL_get_verify_result 来查明证书是否通过了 OpenSSL 的检验。如果证书通过了包括信任检查在内的 OpenSSL 的内部检查,则返回 X509_V_OK。如果有地方出了问题,则返回一个错误代码,该代码被记录在命令行工具的 verify 选项下。

应该注意的是,验证失败并不意味着连接不能使用。是否应该使用连接取决于验证结果和安全方面的考虑。例如,失败的信任验证可能只是意味着没有可信任的证书。连接仍然可用,只是需要从思想上提高安全意识。


清单 12. 检查证书是否有效
if(SSL_get_verify_result(ssl) != X509_V_OK)  {      /* Handle the failed verification */  }  

这就是所需要的全部操作。通常,与服务器进行通信都要使用 BIO_readBIO_write 。并且只需调用 BIO_free_allBIO_reset ,就可以关闭连接,具体调用哪一个方法取决于是否重用 BIO。

必须在结束应用程序之前的某个时刻释放 SSL 上下文结构。可以调用 SSL_CTX_free 来释放该结构。


清单 13. 清除 SSL 上下文
SSL_CTX_free(ctx);  





回页首


错误检测

显然 OpenSSL 抛出了某种类型的错误。这意味着什么?首先,您需要得到错误代码本身; ERR_get_error 可以完成这项任务;然后,需要将错误代码转换为错误字符串,它是一个指向由 SSL_load_error_stringsERR_load_BIO_strings 加载到内存中的永久字符串的指针。可以在一个嵌套调用中完成这项操作。

表 1 略述了从错误栈检索错误的方法。清单 24 展示了如何打印文本字符串中的最后一个错误信息。

表 1. 从栈中检索错误

ERR_reason_error_string 返回一个静态字符串的指针,然后可以将字符串显示在屏幕上、写入文件,或者以任何您希望的方式进行处理
ERR_lib_error_string 指出错误发生在哪个库中
ERR_func_error_string 返回导致错误的 OpenSSL 函数


清单 14. 打印出最后一个错误
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));  

您还可以让库给出预先格式化了的错误字符串。可以调用 ERR_error_string 来得到该字符串。该函数将错误代码和一个预分配的缓冲区作为参数。而这个缓冲区必须是 256 字节长。如果参数为 NULL,则 OpenSSL 会将字符串写入到一个长度为 256 字节的静态缓冲区中,并返回指向该缓冲区的指针。否则,它将返回您给出的指针。如果您选择的是静态缓冲区选项,那么在下一次调用 ERR_error_string 时,该缓冲区会被覆盖。


清单 15. 获得预先格式化的错误字符串
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));  

您还可以将整个错误队列转储到文件或 BIO 中。可以通过 ERR_print_errorsERR_print_errors_fp 来实现这项操作。队列是以可读格式被转储的。第一个函数将队列发送到 BIO ,第二个函数将队列发送到 FILE 。字符串格式如下(引自 OpenSSL 文档):

[pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message]

其中, [pid] 是进程 ID, [error code] 是一个 8 位十六进制代码, [file name] 是 OpenSSL 库中的源代码文件, [line] 是源文件中的行号。


清单 16. 转储错误队列
ERR_print_errors_fp(FILE *);  ERR_print_errors(BIO *);  





回页首


开始做吧

使用 OpenSSL 创建基本的连接并不困难,但是,当试着确定该如何去做时,文档可能是一个小障碍。本文向您介绍了一些基本概念,但 OpenSSL 还有很多灵活之处有待发掘,而且您还可能需要一些高级设置,以便项目能够充分利用 SSL 的功能。

本文中有两个样例。一个样例展示了到 http://www.verisign.com/ 的非安全连接,另一个则展示了到 http://www.verisign.com/ 的安全 SSL 连接。两者都是连接到服务器并下载其主页。它们没有进行任何安全检查,而且库中的所有设置都是默认值 �� 作为本文的一部分,应该只将这些用于教学目的。

在任何支持的平台上,源代码的编译都应该是非常容易的,不过我建议您使用最新版本的 OpenSSL。在撰写本文时,OpenSSL 的最新版本是 0.9.7d。


2007年11月2日星期五

股市看盘秘诀十八条

股市看盘秘诀十八条
       1, 对大盘,大盘股(白线)上得比小盘股(黄线)快,要出现回调,而黄线上涨比白线快,则会带动白线上.

  2,涨跌比率大于1而大盘跌,表明空方势强,反之多方强.此状况高位看跌低位看涨.

  3,成交量大的股票开始走软,或者前期股市的热门板块走软,当小心行情已接近尾声.

  4,股票基本走软,市场在热点消失还没有出现新市场热点的时候,不要轻易去买股票.

  5, 成交量屡创天量,而股价涨幅不大,应随时考虑派发,反之成交量极度萎缩不要轻易抛出股票.

  6,大盘5分种成交明细若出现价量配合理想当看好后市,反之要小心.

  7,成交量若上午太小,则下午反弹的机会多,如上午太大,则下午下跌概率大.

  8,操作时间最好在下午,因为下午操作有上午的盘子作依托,运用60分种K线分析,可靠性好.

  9,上涨的股票若压盘出奇的大,但最终被消灭,表明仍会上涨.

  10,一般股票的升跌贴着均价运行,若发生背离将会出现反转.

  11,盘面经常出现大手笔买卖,买进时一下吃高几个档位,表明大户在进货.

  12, 个股在盘整或下跌时,内盘大于外盘,且阴线实体小,成交量大,日后该股有行情的可能性大;大盘暴跌,而该股没跌多少或者根本没跌,下档接盘强,成交放得很大,后市有戏的可能大.

  13,股价上冲的线头(曲线)绝对的多于下跌的线头时当看好该股.

  14,在下跌的势道里,应选逆势股;在上涨的势道里,应选大手笔买卖的股票.

  15, 开盘数分种就把股价往上直拉,而均线没有跟上,往往都是以当天失败的形式而告终.

  16, 当日下跌放巨量,但收的阴线实体不大,而且大部分时间在昨日收盘以上运行,第二天涨的机会多.

  17, 涨幅在5-7%以上,内盘大于外盘,高点不断创新,低点不断抬高,说明有机构大户在进货.

  18,分价表若是均匀分布说明大户不在里面,否则有大户介入.

--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

2007年10月30日星期二

Regular Express - Clipmarks

Clipmarks user rleon has sent you a clip...

 clipped from www.python.org
"."
(Dot.) In the default mode, this matches any character except a newline. If the DOTALL flag has been specified, this matches any character including a newline.

"^"
(Caret.) Matches the start of the string, and in MULTILINE mode also matches immediately after each newline.

"$"
Matches the end of the string or just before the newline at the end of the string, and in MULTILINE mode also matches before a newline. foo matches both 'foo' and 'foobar', while the regular expression foo$ matches only 'foo'. More interestingly, searching for foo.$ in 'foo1\nfoo2\n' matches 'foo2' normally, but 'foo1' in MULTILINE mode.

"*"
Causes the resulting RE to match 0 or more repetitions of the preceding RE, as many repetitions as are possible. ab* will match 'a', 'ab', or 'a' followed by any number of 'b's.

"+"
Causes the resulting RE to match 1 or more repetitions of the preceding RE. ab+ will match 'a' followed by any non-zero number of 'b's; it will not match just 'a'.

"?"
Causes the resulting RE to match 0 or 1 repetitions of the preceding RE. ab? will match either 'a' or 'ab'.

*?, +?, ??
The "*", "+", and "?" qualifiers are all greedy; they match as much text as possible. Sometimes this behaviour isn't desired; if the RE <.*> is matched against '<H1>title</H1>', it will match the entire string, and not just '<H1>'. Adding "?" after the qualifier makes it perform the match in non-greedy or minimal fashion; as few characters as possible will be matched. Using .*? in the previous expression will match only '<H1>'.

{m}
Specifies that exactly m copies of the previous RE should be matched; fewer matches cause the entire RE not to match. For example, a{6} will match exactly six "a" characters, but not five.

{m,n}
Causes the resulting RE to match from m to n repetitions of the preceding RE, attempting to match as many repetitions as possible. For example, a{3,5} will match from 3 to 5 "a" characters. Omitting m specifies a lower bound of zero, and omitting n specifies an infinite upper bound. As an example, a{4,}b will match aaaab or a thousand "a" characters followed by a b, but not aaab. The comma may not be omitted or the modifier would be confused with the previously described form.

{m,n}?
Causes the resulting RE to match from m to n repetitions of the preceding RE, attempting to match as few repetitions as possible. This is the non-greedy version of the previous qualifier. For example, on the 6-character string 'aaaaaa', a{3,5} will match 5 "a" characters, while a{3,5}? will only match 3 characters.

"\"
Either escapes special characters (permitting you to match characters like "*", "?", and so forth), or signals a special sequence; special sequences are discussed below.

If you're not using a raw string to express the pattern, remember that Python also uses the backslash as an escape sequence in string literals; if the escape sequence isn't recognized by Python's parser, the backslash and subsequent character are included in the resulting string. However, if Python would recognize the resulting sequence, the backslash should be repeated twice. This is complicated and hard to understand, so it's highly recommended that you use raw strings for all but the simplest expressions.

[]
Used to indicate a set of characters. Characters can be listed individually, or a range of characters can be indicated by giving two characters and separating them by a "-". Special characters are not active inside sets. For example, [akm$] will match any of the characters "a", "k", "m", or "$"; [a-z] will match any lowercase letter, and [a-zA-Z0-9] matches any letter or digit. Character classes such as \w or \S (defined below) are also acceptable inside a range. If you want to include a "]" or a "-" inside a set, precede it with a backslash, or place it as the first character. The pattern []] will match ']', for example.

You can match the characters not within a range by complementing the set. This is indicated by including a "^" as the first character of the set; "^" elsewhere will simply match the "^" character. For example, [^5] will match any character except "5", and [^^] will match any character except "^".

"|"
A|B, where A and B can be arbitrary REs, creates a regular expression that will match either A or B. An arbitrary number of REs can be separated by the "|" in this way. This can be used inside groups (see below) as well. As the target string is scanned, REs separated by "|" are tried from left to right. When one pattern completely matches, that branch is accepted. This means that once A matches, B will not be tested further, even if it would produce a longer overall match. In other words, the "|" operator is never greedy. To match a literal "|", use \|, or enclose it inside a character class, as in [|].

(...)
Matches whatever regular expression is inside the parentheses, and indicates the start and end of a group; the contents of a group can be retrieved after a match has been performed, and can be matched later in the string with the \number special sequence, described below. To match the literals "(" or ")", use \( or \), or enclose them inside a character class: [(] [)].

(?...)
This is an extension notation (a "?" following a "(" is not meaningful otherwise). The first character after the "?" determines what the meaning and further syntax of the construct is. Extensions usually do not create a new group; (?P<name>...) is the only exception to this rule. Following are the currently supported extensions.

(?iLmsux)
(One or more letters from the set "i", "L", "m", "s", "u", "x".) The group matches the empty string; the letters set the corresponding flags (re.I, re.L, re.M, re.S, re.U, re.X) for the entire regular expression. This is useful if you wish to include the flags as part of the regular expression, instead of passing a flag argument to the compile() function.

Note that the (?x) flag changes how the expression is parsed. It should be used first in the expression string, or after one or more whitespace characters. If there are non-whitespace characters before the flag, the results are undefined.

(?:...)
A non-grouping version of regular parentheses. Matches whatever regular expression is inside the parentheses, but the substring matched by the group cannot be retrieved after performing a match or referenced later in the pattern.

(?P<name>...)
Similar to regular parentheses, but the substring matched by the group is accessible via the symbolic group name name. Group names must be valid Python identifiers, and each group name must be defined only once within a regular expression. A symbolic group is also a numbered group, just as if the group were not named. So the group named 'id' in the example above can also be referenced as the numbered group 1.

For example, if the pattern is (?P<id>[a-zA-Z_]\w*), the group can be referenced by its name in arguments to methods of match objects, such as m.group('id') or m.end('id'), and also by name in pattern text (for example, (?P=id)) and replacement text (such as \g<id>).

(?P=name)
Matches whatever text was matched by the earlier group named name.

(?#...)
A comment; the contents of the parentheses are simply ignored.

(?=...)
Matches if ... matches next, but doesn't consume any of the string. This is called a lookahead assertion. For example, Isaac (?=Asimov) will match 'Isaac ' only if it's followed by 'Asimov'.

(?!...)
Matches if ... doesn't match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match 'Isaac ' only if it's not followed by 'Asimov'.

(?<=...)
Matches if the current position in the string is preceded by a match for ... that ends at the current position. This is called a positive lookbehind assertion. (?<=abc)def will find a match in "abcdef", since the lookbehind will back up 3 characters and check if the contained pattern matches. The contained pattern must only match strings of some fixed length, meaning that abc or a|b are allowed, but a* and a{3,4} are not. Note that patterns which start with positive lookbehind assertions will never match at the beginning of the string being searched; you will most likely want to use the search() function rather than the match() function:

>>> import re >>> m = re.search('(?<=abc)def', 'abcdef') >>> m.group(0) 'def' 

This example looks for a word following a hyphen:

>>> m = re.search('(?<=-)\w+', 'spam-egg') >>> m.group(0) 'egg' 

(?<!...)
Matches if the current position in the string is not preceded by a match for .... This is called a negative lookbehind assertion. Similar to positive lookbehind assertions, the contained pattern must only match strings of some fixed length. Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched.

(?(id/name)yes-pattern|no-pattern)
Will try to match with yes-pattern if the group with given id or name exists, and with no-pattern if it doesn't. |no-pattern is optional and can be omitted. For example, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>) is a poor email matching pattern, which will match with '<user@host.com>' as well as 'user@host.com', but not with '<user@host.com'. New in version 2.4.

Get Clipmarks - The easiest way to email text, images and videos you find on the web. It's free!
Sent with Clipmarks

2007年10月29日星期一

Emacs中加入自己编码识别

强大的编辑器要有强大的编码识别能力 -- unicad.el

如果你经常要查看或编辑多种国家语言的文件,那你可能经常碰到乱码的情况。

unicad.el 是从 Mozilla universal charset auto detector 改写过来的 Elisp 程序,在 GNU Emacs 里加载上 unicad 就可以自动识别多种编码,以后再也不会遇到乱码的文件了。把下载到的 unicad.el 复制到 Emacs 的 load-path 里,比如 site-lisp ,在 ~/.emacs 里加上下面这句:

(require 'unicad)

如果你觉得检测过程拖慢了打开文件的速度,可以 byte-compile 这个文件:

M-x byte-compile-file <RET> /path/to/unicad.el

超载地址 http://cid-3643184002e3d5e6.skydrive.live.com/self.aspx/Public/unicad.zip

--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

Emacs code-publish

;;; code-publish.el --- convert codes into html, used for msn space
;; Because of the limited allowed file types,
;; if the extension of this file is not .el, please change it manually.

;; Author: Qichen Huang <jasonal00+emacs at gmail.com>
;; Version: 0.2

;;; Commentary:
;; (require 'code-publish)

;; Usage:
;; M-x code-publish
;; the converted html code will be copied to kill-ring,
;; which could be directly pasted onto msn space as html code.

;; History:
;; 14.08.2006 Version 0.2
;; 14.08.2006  Added: tag <div>
;; 28.07.2006 Version 0.1

;;; Code:

(defun code-publish ()
  "Convert region between mark and point into HTML, save the result into kill ring."
  (interactive)
  (kill-new (code-publish-region (mark) (point)))
  (message "Code convert completed."))



(defvar font-header "<font size=\"2\">")
(defvar div-header "<div style=\"background-color:rgb(255,255,224);\">")
(defvar footer "</div></font>")
(defvar tag-open "<span style=\"font-family: Courier New,Courier,Monospace;")
(defvar tag-close ">")
(defvar tag-end "</span>")
(defvar newline-tag "<br>")
(defvar space "&nbsp;")
(defvar space2 "&nbsp;&nbsp;")
(defvar space4 "&nbsp;&nbsp;&nbsp;&nbsp;")

(defvar code-builtin-color       " color: rgb(0,139,0);\"")
(defvar code-comment-color       " color: rgb(205,0,0); font-style: italic;\"")
(defvar code-constant-color      " color: rgb(47,79,79);\"")
(defvar code-doc-color           " color: rgb(0,139,0);\"")
(defvar code-function-name-color " color: rgb(0,0,255); font-weight: bold;\"")
(defvar code-keyword-color       " color: rgb(160,32,240);\"")
(defvar code-preprocessor-color  " color: rgb(250,128,114);\"")
(defvar code-string-color        " color: rgb(0,139,0);\"")
(defvar code-type-color          " color: rgb(0,0,128);\"")
(defvar code-variable-name-color " color: rgb(139,90,40);\"")
(defvar code-warning-color       " color: rgb(255,0,0);\"")
(defvar code-default-color       " \"")

(defun code-publish-region (begin-point end-point)
  (let ((beg (min begin-point end-point))
        (end (max begin-point end-point))
        (str "")
        (tmp nil)
        (result nil)
        (tface nil)
        (color "")
        )
    ;;(beginning-of-buffer)
    (unless (= beg end)
      (save-excursion
        (setq result (concat result font-header))
        (setq result (concat result div-header))
        (goto-char beg)
        (while (< (point) end)
          (setq tmp (next-single-property-change (point) 'face))
          (unless tmp
            (setq tmp end)) ;; there is no face change, set tmp to end point
          ;; no cross-line properties
          (when (> tmp (line-end-position))
            (setq tmp (line-end-position))) ;; New line
          ;; skip spaces and tabs
          (save-excursion
            (goto-char tmp)
            (when (looking-at "[ \t]+")
              (re-search-forward "[ \t]+" (line-end-position) t)
              (setq tmp (point))))
          (when (> tmp end)
            (setq tmp end))
          (setq str (buffer-substring-no-properties (point) tmp))
          (while (string-match "<" str)
            (setq str (replace-match "&lt;" t nil str)))
          (while (string-match ">" str)
            (setq str (replace-match "&gt;" t nil str)))
          (while (string-match "  " str)
            (setq str (replace-match space2 t nil str)))
          (while (string-match "\t" str)
            (setq str (replace-match space4 t nil str)))
          (setq tface (get-text-property (point) 'face))
          (when (listp tface)
            (setq tface (car tface)))
          (cond
           ((eq tface font-lock-builtin-face)
            (setq color code-builtin-color))
           ((eq tface font-lock-comment-face)
            (setq color code-comment-color))
           ((eq tface font-lock-constant-face)
            (setq color code-constant-color))
           ((eq tface font-lock-doc-face)
            (setq color code-doc-color))
           ((eq tface font-lock-function-name-face)
            (setq color code-function-name-color))
           ((eq tface font-lock-keyword-face)
            (setq color code-keyword-color))
           ((eq tface font-lock-preprocessor-face)
            (setq color code-preprocessor-color))
           ((eq tface font-lock-string-face)
            (setq color code-string-color))
           ((eq tface font-lock-type-face)
            (setq color code-type-color))
           ((eq tface font-lock-variable-name-face)
            (setq color code-variable-name-color))
           ((eq tface font-lock-warning-face)
            (setq color code-warning-color))
           (t (setq color code-default-color)))
          ;; (setq color "<span color=\"\">")
          (setq result (concat result tag-open color tag-close str tag-end))
          (when (= tmp (line-end-position))
            (setq result (concat result newline-tag))
            (setq tmp (+ 1 (line-end-position))))
          (goto-char tmp))
        (setq result (concat result footer))
        result
        ))))

(provide 'code-publish)

;;; ################ code-publish ends here #######################

Emacs中建立文件自动关联mode

一次性关联
(
setq auto-mode-alist
;; 将文件模式和文件后缀关联起来。
( append '(("\\.py\\'" . python-mode)
("\\.s?html?\\'" . html-helper-mode)
(" \\.asp\\'" . html-helper-mode)
("\\.phtml\\'" . html-helper-mode)
("\\.css\\'" . css-mode) )
auto-mode-alist)
)
单个文件关联
(add-to-list 'auto-mode-alist '("\\.org$" . org-mode))


--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

【转帖】如何不重新启动 Emacs 就让 .emacs 的配置起作用

我刚刚使用 Emacs 的时候,总是

vi ~/.emacs

然后重新启动 emacs ,效率很低 ,暗自嘟囔, emacs 怎么没有这种功能,不重起,就自动更新 .emacs 的设置 呢?

后来我发现,这个功能完全没有必要,我的做法是:

  • 用 emacs 打开 .emacs 文件,C-x C-e 光标前面的运行一条语句。立即生效。
  • 选择一个 region , M-x eval-region
  • M-x load-file ~/.emacs
  • M-x eval-buffer

都是立即生效,可以马上试验一条语句的效果。 例如,在任何一个文件中,写

(setq frame-title-format "emacs@%b")

把光标停在在这条语句后面, C-x C-e ,马上看到 emacs 的 标题栏上发生变化。

我用这种方法调试我的每一个小的配置文件,按上篇文章说的方法, 把他放在 ~/Emacs/myconfig/my-site-start.d 中。



--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

Emacs 在窗口的标题栏上显示文件名称

在窗口的标题栏上显示文件名称
(setq frame-title-format "%n%F/%b")
% 后面跟一个特殊字符表示特殊的意义。

--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

2007年10月24日星期三

编程内核


 make-kpkg --revision tchai.0818 \
          --append-to-version .kov \
          --config menuconfig \
            kernel_image modules_image


make-kpkg --rootcmd fakeroot \
          --revision tchai.0818 \
          --append-to-version .kov \
          --config menuconfig \
            kernel_image modules_imageo


有时还是直接编译成binary-arch好,还可以生成kernel-headers,方便其它模块的编译, 比如alsa
nvidia等。。。

对于2.4的,偶经常是
$make-kpkg --rootcmd fakeroot binary-arch
对于2.6的,
$make-kpkg --rootcmd fakeroot --initrd binary-arch

需要的时候直接dpkg -i安装上。

make-kpkg --revision $1 --append-to-version $2 kernel_image modules_image



--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

直接从XP/W2K下通过硬盘启动来进行Ubuntu网络安装

直接从XP/W2K下通过硬盘启动来进行网络安装

只需要下载6M的文件,就可以从XP/W2K下通过硬盘启动来进行网络安装。
一:安装GRUN
  1. 下载GRUB   GRUB
  2. grldr 复制到 C:\,编辑C:\BOOT.INI,加入一行:
    C:\GRLDR="GRUB"
    注意:在下载的过程中,IE有时会自动加上.Dat的扩展名,如果如此,将文件名 grldr.dat 改为 grldr .

二:下载并设置安装包

1.   下载 netboot.tar.gz

2.   解压缩,提取 ubuntu-install/i386/ 目录下的 linuxinitrd.gz 到 C:\

三:重新启动计算机,按 c 进入 grub 命令行 根据下载的文件存放的位置,输入并回车:
    grub>kernel (hd0,0)/linux root=/dev/ram ramdisk_size=20000 devfs=mount,dall

    grub>initrd (hd0,0)/initrd.gz

    grub>boot

    这样,就可以开始安装了。

    注意:如果使用代理服务器或自己内部的源,有可能出现长时间的停顿,一共会出现两次。第一次手工设置完毕镜像后,如果出现停顿,使用 Alt+F2 切换到其它的控制台,使用 ps -LA 查看全部进程,将两个 wget 的进程 kill 掉,就可以再使用 alt+F1 切换回去,进行下一步的代理服务器设置,第二次也是在设置镜像之后。同样切换到控制台使用 ps -LA 查看全部进程,将一个最后名为 http 的进程 kill 掉,就可以同样再使用 alt+F1 切换回去开始安装系统了。

--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

做张grub启动盘

http://dev.csdn.net/article/70/70523.shtm

有时候我们的电脑可能出现系统无法引导的情况,比如说你重装了windows,把MBR给重写了,又比如像我今天这样,把装了grub的系统给格了,电脑启动后无法读到引导信息出错,什么系统都进不了了。
这时你当然可以用安装时或什么管你什么时候做的启动盘启动LINUX(然后再进行修复),用windows启动盘启动windows。
但这样你得至少做两张启动盘啊(呵呵,当然用loadlin之类的也行,不过我觉得更麻烦)。而且你每装一个LINUX就得做一张启动盘,不是很麻烦吗?
其实没有那么麻烦,只要你用grub做的引导,就很容易了,那么就是做一张grub启动盘.
这样你就相当于把grub装到了软盘上,利用一些grub命令就可以做到你的MBR没有被破坏前能做的所有事。而且,你在A机器上做的启动盘还可以拿到B、C、D……等等其它机器上用。
制作方法:

首先你用的引导程序必须是grub。
确认了这一点之后进入/boot/grub目录:
cd /boot/grub
然后把stage1和stage2两个文件写到你的软盘上去(呵呵,当然别忘了把软盘放进去哦):
dd if=stage1 of=/dev/fd0 bs=512 count=1
dd if=stage2 of=/dev/fd0 bs=512 seek=1

这样一张grub引导盘就做好了,下面就谈谈使用方法(虽然很简单,但还是怕有人不清楚)

首先用这张启动盘启动后会出现一些关于grub的信息,然后就是如下:
grub>
这就是在等你输入grub命令来启动系统。
对于LINUX,一般需要如下三个命令:
root,kernel,boot.
ROOT命令就是让你告诉GRUB,你的LINUX系统装在哪个分区,KERNEL命令就是让你指出用哪个内核启动,BOOT当然就是开始引导啦。
举个例子:
grub>root (hd0,
File system Type is ext2fs.(这一行告诉你文件系统是什么,详细的显示内容可能跟我写的不一样)
grub>kernel /boot/vmlinuz ro root=/dev/hda9
grub>boot

这样你的LINUX系统就启动了,注意的一点是GRUB中关于分区的叫法跟LINUX有点不一样,比如上面的(hd0,就表示hda9.是的,hdX就代 表第X+1个硬盘,hd0就代表第1个硬盘(相当于hda),8就代表第9个分区(GRUB中的表示方法跟C语言有点像,下标是从0开始的),(hd0, 当然就是代表hda9啦。
知道这些应该知道怎么引导LINUX系统了吧?注意一点,如果你不清楚具体的内核文件名(比如有的可能是vmlinuz-2.4.20什么的),那么你可 以用TAB键自动补全,相当方便,你只要打入kernel /boot/vm然后再按一下TAB键,那么就会显示全部在/boot/下以vm开头的文件。

引导其它系统就方便多了(比如windows,FreeBSD等),你要做的也是三个命令,ROOT跟BOOT命令跟LINUX一样,反正就是用ROOT 命令指定你装的这个系统所在的分区,BOOT命令就是开始引导系统。不同的是把引导linux的kernel命令改成chainloader +1命令。例如:

grub>root (hd0,0)
File System Type Vfat
grub>chainloader +1
grub>boot


呵呵,好了,把你做好的grub启动盘好好保存起来吧,以后装LINUX的时候它如果问你要不要做启动盘时你都可以大胆地说:NO!。因为你的这张grub启动盘基本上可以应付大部分无法启动的情况了。
呵呵,不过这种启动盘无法应付严重的系统错误(比如内核文件受到破坏什么的等等),但是这样的情况我还没有遇见过,我需要启动盘的情况往往是因为引导程序出了问题,比如重装WINDOWS,比如GRUB被我搞掉了等等。'



--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/

2007年10月22日星期一

用Emacs+Muse来记笔记--Muse的配置

用Emacs+Muse来记笔记--Muse的配置

论坛里很少有关于EmacsWiki或者EmacsMuse的帖子
我写了一份配置说明,供大家参考
好像论坛里不能直接看我做的网页
大家可以把附件下载下来然后用浏览器看
的确很漂亮哦:)


Contents

前记
感谢
安装

Debian/Ubuntu系统上的安装

配置使用

基本配置
Projects的管理

"并排"方式
"目录树"方式

自定义派生的style

"并排"方式的派生style设置
"目录树"方式派生style设置

Google的搜索栏
导航菜单

自定义的函数

ywb-muse-relative-path
ywb-muse-html-markup-table
ywb-muse-publish-math-tab
ywb-muse-publish-src-tag
ywb-muse-handle-file-link
使contents更漂亮
给每个标题加个top锚
ywb-muse-publish-project
ywb-muse-output-file
ywb-muse-publish-this-file
ywb-muse-generate-index
ywb-muse-preview-with-w3m
ywb-muse-preview-html
ywb-muse-preview-source

3.02.90 版中的一些问题

解决方法

环境变量设置
Planner抄来的配置
快捷键设置
相关链接

Muse相关
EmacsWiki相关

top前记
最早看到用Emacs写WiKi的人应该是王垠吧,后来感觉最流行和最好看的WiKi就应该是薛瑞尼的了。但是现在Emacs Wiki的作者Michael Olson已经不维护Emacs Wiki这个项目了,而是维护一个类似的但功能更强大的项目Muse。而Muse有一些功能还不是很完善,于是我在Google和 Emacs@newsmth之间游走,到处找人帮忙,终于弄出了一个感觉还不错的配置文件,虽然有一些地方还不完善,但是还是先写出来,来以飨大家,其实更重要的是抛砖引玉,使Muse的配置更完善。如果大家对配置或者其中有一些函数进行改进,请尽量保留原作者的信息。
top感谢
叶文彬—几乎所有自定义的函数和大多数配置都是他写的,我都有些不好意思而求他了:)所以下面配置文件里所有带ywb字样的函数请保留,以表示对他的感谢。

薛瑞尼—我的css文件基本上是改他的,的确很漂亮。他也提供了他的配置文件供我参考。

其他人—我参考的其他人用Muse写的网页或者用Emacs-WiKi写的网页。
top安装
可以到Michael Olson的主页上去下载最新版

http://www.mwolson.org/projects/EmacsMuse.html

你也可以到下面的地址去下载最新release的tar.gz格式或者zip格式的包。

http://www.mwolson.org/static/dist/muse/

topDebian/Ubuntu系统上的安装
如果你用Debian的话,在etch(testing)和sid(unstable)里 已经有3.02.6-2这个版本了,所以只要

apt-get install muse-el

就可以了。如果想要装最新的版本,请在你的/etc/apt/sources.list加入下面的源然后更新安装即可。

deb http://www.mwolson.org/debian/ ./

你也可以到下面的地址去下载最新release的deb包然后直接dpkg -i muse-el_***.deb安装即可。

http://mwolson.org/debian/

现在我装的版本是3.02.92.arch.193-1,刚刚看到Olson已经把Muse开发到3.03了,但是not yet released,呵呵,好像增加了好多新特性,如果你要看看有什么新东西的话看这里 NEWS-3.03,或者看我下载的这个NEWS-3.03

如果用是用Ubuntu,我没有测试过,不知道源里有没有,但是上面添加 Michael Olson所提供的源然后安装的方法一定是可以的。
top配置使用
配置使用可以去Emacs Wiki: Muse Mode看看。

http://www.emacswiki.org/cgi-bin/wiki/MuseMode

也可以参考别人的,我这里尽量把我所知道的都写出来。我的配置文件在这里:

muse-init.el
top基本配置

Muse之所以功能强大,最重要的是能输出很多种格式的文件,但是如果只写网页的话只要几样就行了。所以下面配置里前面注掉的都是你可以选择的,如果你要输出其它格式的文件的话,请参考Muse自的带的文档说明。

;;; muse-init.el --- Initialize muse-mode.
;;;; Add below to ~/.emacs config file
;(load-file "~/.emacs.d/conf/muse-init.el")
;(add-to-list 'load-path "/usr/share/emacs/site-lisp/muse-el/experimental")
;;;; xhtml footer and header (如果你沿用emacs-wiki那样定义多个项目而不用muse子目录发布功能,注掉它,这个在后面会说明)
(load-file "~/.emacs.d/conf/muse-footer-header.el")
(require 'muse) ; load generic module
(require 'muse-mode nil t) ; load authoring mode
(require 'muse-wiki nil t) ; load Wiki support
(require 'muse-html nil t) ; load (X)HTML publishing style
(require 'muse-colors nil t) ; load coloring/font-lock module
(require 'outline nil t)
(require 'sgml-mode)
(require 'tp-muse-highlight nil t)
;;;;(下面的可选,我没有用到)
;(require 'muse-blosxom) ; load blosxom module
;(require 'muse-docbook) ; load DocBook publishing style
;(require 'muse-latex) ; load LaTeX/PDF publishing styles
;(require 'muse-texinfo) ; load Info publishing style
;(require 'muse-xml) ; load XML support
;(require 'muse-journal) ; load journal module
;(require 'muse-message) ; load message support (experimental)
;(require 'muse-srctag) ; load srctag support

tp-muse-highlight.el
topProjects的管理
Muse在projects的定义和管理方面做得比Emacs Wiki好,可以省去很多麻烦。projects之间的引用也很方便。而且有一项新功能是从blosxom那里学来的,就是可以把一个源文件的目录树相应地发布成html文件,而发布的目录树的结构跟源文件目录树的结构相同。但是这样也存在一些问题,比如说css文件、图片或者其它的一些东西的相对路径不能自动处理。但是叶文彬写了一些函数可以来解决这个问题。所以projects的管理我分种方法来说明,一种是像Emacs Wiki那样的组织多个"并排"的projects,另一种是"目录树"结构。下面分别介绍:
top"并排"方式
这种方式最简单,其实也最实用,唯一不爽的就是你得把所有的projects的源文件和发布文件都并排地放到一起,没有层次感。不过也并不是每个人都像我一样喜欢用树状结构来分类吧:)

(setq muse-project-alist
`(
("Debian" ;项目名称
("~/muse/source/wiki/debian" ;源文件的位置
:default "index" ;默认的project的主页
:force-publish ("WikiIndex"));发布项目时同时发布project的索引文件
(:base "wiki-xhtml" :path "~/muse/publish/wiki/debian")) ;发布路径
("Emacs"
("~/muse/source/wiki/emacs"
:default "index"
:force-publish ("WikiIndex"))
(:base "wiki-xhtml" :path "~/muse/publish/wiki/emacs"))
("GNU"
("~/muse/source/wiki/gnu"
:default "index"
:force-publish ("WikiIndex"))
(:base "wiki-xhtml" :path "~/muse/publish/wiki/gnu"))
))

top"目录树"方式
如果你像我一样平时收集了一堆从网上弄来的Linux相关的Tips啦,文章啦,而看着这一堆的东西太乱了,于是分门别类地建了一堆目录来分类,而目录下可能还有子目录。那在组织 projects时也想这么干吧。Muse中有一个设置muse-project-alist-dirs可以来干这个,并且把这个你定义的project下的所有目录树结构记住,在发布成html文件时相应地按源文件的目录树结构来发布到指定的目录下。

(setq muse-project-alist
`( ;!注意这一行最左边的是一个"`",ESC键下面那个!
("Muse"
("~/muse/source/wiki/gnu/emacs/muse"
:default "MuseIndex"
:force-publish ("index"))
(:base "wiki-xhtml" :path "~/muse/publish/wiki/gnu/emacs/muse"))
("Debian"
("~/muse/source/wiki/gnu/debian"
:default "index"
:force-publish ("WikiIndex"))
(:base "wiki-xhtml" :path "~/muse/publish/wiki/gnu/debian"))
("Emacs"
("~/muse/source/wiki/gnu/emacs"
:default "index"
:force-publish ("WikiIndex"))
(:base "wiki-xhtml" :path "~/muse/publish/wiki/gnu/emacs"))
("GNU"
("~/muse/source/wiki/gnu"
:default "index"
:force-publish ("WikiIndex"))
(:base "wiki-xhtml" :path "~/muse/publish/wiki/gnu"))

("WiKi" (,@(muse-project-alist-dirs "~/muse/source/wiki");源文件路径
:default "index" ;默认项目主页
:force-publish ("WikiIndex")
)
,@(muse-project-alist-styles "~/muse/source/wiki" ;还是源文件路径
"~/muse/publish/wiki" ;发布路径
"wiki-xhtml"))
("Others"
("~/muse/source/others"
:default "index"
:force-publish ("WikiIndex"))
(:base "xhtml" :path "~/muse/publish/others"))

("Default" (,@(muse-project-alist-dirs "~/muse/source/default")
:default "index"
:force-publish ("WikiIndex"))
,@(muse-project-alist-styles "~/muse/source/default"
"~/muse/publish"
"default-xhtml"))

))

肯定有人会问,既然都用子目录结构了,为什么还定义那些子projects呢?因为目录树的这个功能很有限,他只会把相应文件发布并按目录树结构安装,而如果你还是想把Emacs、 Debian、GNU这些做为projects,方便项目之间的引用的话,还得在写上这些项目的定义。而且写法也得按一定的"规矩"来,这个"规矩"是:

* 1.源文件目录中最上层目录放到项目定义的最下面

配置中的WiKi就得安排在Muse、Debian、Emacs、GNU的下面,因为这些"子"项目所在的目录都在 WiKi的目录中,是它的子目录。

* 2.项目在配置文件里的设置是根据目录的层数的深度来确定位置,原则是层数深的不能在层数浅的上面

配置中Muse的目录比Debian和Emacs的深,所以在它们俩的上面,而相同深度的就随便谁在上谁在下都行。

* 3.如果两个项目没有目录树间的关系,可以随便写。

比如说Others就可以写在下面。

这个是我实验过很多次得出的最好的方法。因为在header和footer里有一些处理项目名称的函数,这样写不会出乱子。
top自定义派生的style
Muse之所以能生成多种格式的文件的原因之一我想可能就是这个功能了,在输出html格式方面,你可以自定义你的html文件的header和footer,这样使用起来很方便。其他输出文件格式请参考Muse文档。但是因为有了上面的Projects的管理的两种配置方法,这里也要相应地跟着变化。
top"并排"方式的派生style设置
这个也最简单,定义一个派生的style,把你想要的header.html和footer.html的路径写上可以了。而这两个文件是按照html的语法来写的,在发布时直接把其中的内容拷到发布的 html文件里。

(unless (assoc "my-blosxom" muse-publishing-styles)
(muse-derive-style "wiki-xhtml" "xhtml" ;定义一个派生的style为wiki-xhtml
:header "~/muse/common/templates/header.html"
:footer "~/muse/common/templates/footer.html"
)
(muse-derive-style "default-xhtml" "xhtml" ;定义另一个派生的style
:header "~/muse/common/templates/default- header.html"
:footer "~/muse/common/templates/default-footer.html"
))

如果要对其中一些可变的内容用lisp函数来处理理,可以在其中嵌入lisp函数,比如说我在 footer.html里要设定网页发布的时间,就可以加上这么变态的几句来处理:

最后更新:
<lisp>
(format-time-string "%4Y-%2m-%2d-%T"
(nth 5 (file-attributes
muse-publishing-current-file)))
</lisp>

然后效果就是:

最后更新: 2006-08-25-23:23:19

我的header.html和footer.html你可以参考一下。文件的内容可以看这里:

header.html

footer.html

下载在这里:

common/templates/header.html

common/templates/footer.html
top"目录树"方式派生style设置
因为要处理html文件里css和图片的相对路径的问题,所以按上面"并排"的方式设置派生 style是有些问题的。我实验过,css文件的路径处理可以在header.html里用 ywb-muse-relative-path函数来处理(这个函数在下面会介绍,不要急:),像这样:

<link rel="stylesheet" type="text/css" charset="utf-8" media="all"
href="<lisp>(ywb-muse-relative-path "common/stylesheets/core.css")</lisp>" />

但是对于图片链接就不行了比如说这个:

<a href="http://www.mwolson.org/projects/EmacsMuse.html">
<img style="border: 0em none ;"
src=" <lisp> (ywb-muse-relative-path "common/images/muse- powered-by.png")</lisp> " alt="Emacs Muse Logo"></a>

可能是因为elisp的或者是html对"""的处理问题吧。那现在怎么办呢?其实很简单,可以入到muse-init.el中,如果要写到emacs的配置文件里去在每一个"""前加一个"\"来转义就可以了。也可以单独写一份文件叫muse-header-footer.el ,在加载muse-init.el时同时加载它就行了。

;;; muse-init.el --- Initialize muse-mode.
;;;; Add below to ~/.emacs config file
;(load-file "~/.emacs.d/conf/muse-init.el")
;;;; xhtml footer and header (如果你沿用emacs-wiki那样定义多个项目而不用muse子目录发布功能,注掉它,这个在后面会说明)
(load-file "~/.emacs.d/conf/muse-footer-header.el")

文件的内容可以看这里:

muse-header-footer_el.html

下载在这里:

muse-header-footer.el
topGoogle的搜索栏
我是参考邢兆鹏的,只在要header里的<h1>title</h1>加上下面这段就行了。那个Google图片也是从他网站上拷下来的,希望他不介意:)

<h1>
<lisp>(muse-publishing-directive \"title\")</lisp>
<!-- Google Search -->
<div class=\"searchbar\">
<form id=\"searchbar\" method=\"get\" action=\" http://www.google.com/custom\" title=\"My Site Search\">
<div id=\"searchbar\">
<label for=\"q\" title=\"Search this site\">
<img src=\"<lisp> (ywb-muse-relative-path \"common/images/google.gif\")</lisp>\" ></label>
<input type=hidden name=domains value=\" http://www.yoursite.org/\">
<input type=hidden name=sitesearch value=\"http://www.yoursite.org/\">
<input type=\"text\" id=\"q\" name=\"q\" accesskey=\"s\" size=\"16\">
<input type=\"submit\" id=\"submit\" value=\"Go\">
</div>
</form>
</div>
<!-- Google Search -->
</h1>

如果要你用"并排"方式来设置projects,那么请把上面所有的"\"去掉,然后加到 header.html里。当然我已经给弄好了一份,可以看上面的两小节。
top导航菜单
跟Google搜索栏相似,在header.html里的最后加入下面的内容就行了。其实会lisp语言的话还可做的更灵活:)

<!-- menu start here -->
<div class=\"menu\">
<div class=\"menuitem\">
<a href=\" <lisp> (ywb-muse-relative-path \"index.html\")</lisp>\">Home</a>
</div>
<div class=\"menuitem\">
<a href=\" <lisp> (ywb-muse-relative-path \"wiki/index.html\")</lisp>\">WiKiNotes</a>
</div>
</div>
<!-- menu ends here -->

top自定义的函数
这些函数可以在叶文彬的Muse配置文件里找到:

http://learn.tsinghua.edu.cn:8080/20...csMusecof.html

他写的关于Muse的说明:

http://learn.tsinghua.edu.cn:8080/20...EmacsMuse.html
topywb-muse-relative-path
如果你想用Projects的管理方式中的"目录树"方式,这个函数可以说是写的极好,肯定必用!

(defun ywb-muse-relative-path (file)
(concat
(file-relative-name
my-muse-publish-directory
(file-name-directory muse-publishing-current-output-path))
file))

这个函数用于子目录发布,在发布的过程中推断出相对路径。有了这个函数,对于 css 或者图片名, 在muse-init.el或者muse-header-footer.el这样写就行了:

<lisp>(ywb-muse-relative-path \"css/core.css\")</lisp>

css/core.css 是相对于 my-muse-publish-directory 的路径。而my-muse-publish-directory是个变量,定义如下:

(defvar my-muse-publish-directory "~/muse/publish/")

* 说明:

这个变量和函数的作用,这个变量是跟定义了你的所有要发布文件要发布到哪个目录中去,而在你的这个目录中(~/muse/publish/)如果有一个文件夹为css,里面有个core.css 的文件,那么把这个函数放到xhtml的头文件的定义中去来代替里面的css文件的路径位置, 然后在发布过程中这个函数会把core.css这个文件相对于(~/muse/publish/)这个目录的相对路径输出到html文件里,所以对于放着我的这个html网页和其它文件的这个文件夹来说,只要目录里的文件和文件夹的相对位置不变,那么无论把这个文件夹放到谁的机器上还是放到服务器上,你用浏览器打开这个网页都能正常显示,因为css文件的路径是相对的,而底下的那一排图标的路径也是相对的。我问过Olson这个问题,他要我用绝对路径,他的网站上所有的css文件和图片的路径都是绝对路径。可是我还没有服务器上传,我只想在本机上看,用绝对路径在本地看肯定不行了。所以我觉得这个函数很棒,真是非常感谢叶文彬:)
topywb-muse-html-markup-table

;;;;_+ ywb-muse-html-markup-table
(defun ywb-muse-html-markup-table ()
(let ((str (match-string 1)))
(when (= (aref str 0) ?|)
(save-excursion
(save-match-data
(let ((endmarker (set-marker (make-marker) (match-end 0)))
(start (match-beginning 0))
(nextline (lambda () (forward-line 1) (point))))
(goto-char (1+ start))
(when (looking-at "|\\([-]+[|+]\\)+[ \t]*$")
(delete-region (point) (funcall nextline))
(perform-replace "[ \t]+|[ \t]+" " || " nil t nil nil nil
(point) (funcall nextline))
(delete-region (funcall nextline) (funcall nextline)))
(goto-char endmarker)
(forward-line -1)
(when (looking-at "|\\([-]+[|+]\\)+[ \t]*$")
(delete-region (point) (funcall nextline)))
(perform-replace "^|[ \t]*" "" nil t nil nil nil start endmarker)
(perform-replace "|[ \t]*$" "" nil t nil nil nil start endmarker)))))
(muse-html-markup-table)))

topywb-muse-publish-math-tab
org-mode 可以发布一些具有上标和下标的html代码。可以借来用一下。

;;;;_+ ywb-muse-publish-math-tab
(defun ywb-muse-publish-math-tab (beg end attrs)
(require 'org)
(let ((tag (or (cdr (assoc "tag" attrs)) "span")))
(insert (concat "<" tag " class=\"math\">"
(org-export-html-convert-sub-super
(delete-and-extract-region beg end))
"</" tag ">\n"))
(muse-publish-mark-read-only beg (point))))

topywb-muse-publish-src-tag
语法加亮。本网页中的emacs-lisp语法加亮都是用这个函数来实现的。

;;;;_+ ywb-muse-publish-src-tag
(defun ywb-muse-publish-src-tag (beg end attrs)
(let ((mode (cdr (assoc "type" attrs))))
(tp-muse-fontified-example-tag beg end nil
(intern-soft (concat mode "-mode")))))

topywb-muse-handle-file-link
处理文件链接的函数。

;;;;_+ ywb-muse-handle-file-link
(defun ywb-muse-handle-file-link (&optional string)
(or string
(setq string
(let ((end (save-excursion
(re-search-forward "]" nil t)
(1- (point)))))
(when end
(buffer-substring-no-properties (point) end)))))
(setq string
(expand-file-name
(concat (muse-get-keyword :path (nth 2 (muse-project)))
"/" string)))
(when (file-exists-p string)
string))

下面的这几句我看不太懂,但意思差不多明白,应该是把上面那些自定义的有增强功能的函数加到 Muse自带的相应函数里去。反正照写就是啦:)

;;;;_+
(add-to-list 'muse-html-markup-functions '(table . ywb-muse-html-markup-table))
(add-to-list 'muse-html-markup-tags '("math" t t ywb-muse-publish-math-tag))
(add-to-list 'muse-html-markup-tags '("src" t t ywb-muse-publish-src-tag))
(add-to-list 'muse-explicit-link-functions 'ywb-muse-handle-file-link)

top使contents更漂亮
因为薛瑞尼的css文件对contents做了一些设置,并用了一个好看的小图片(就是最上面 Contents中那一排金色的小圆圈),看了他的配置文件才知道,其实他是加了一层 contents,并且改用了sacha写的一个函数,我开始改写了这个函数,但是虽然Contents好看了,然后所有的标题里的内容都跑到外面去了,叶文彬指出了错误所以在(处理时多输出了一个回车),于是重新改写于下:

;;;_+ insert contents. contents should strip all the tags
(defun ywb/muse-publish-strip-tags (string)
(while (string-match "<.*?>" string)
(setq string (replace-match "" nil t string)))
string)
(defadvice muse-publish-contents-tag (around ywb activate)
(let* ((beg (ad-get-arg 0))
(end (ad-get-arg 1))
(attrs (ad-get-arg 2))
(max-depth (let ((depth (cdr (assoc "depth" attrs))))
(or (and depth (string-to-int depth)) 3)))
(index 1)
base contents l)
(save-excursion
(catch 'done
(while (re-search-forward "^\\(\\*+\\)\\s-+\\(.+\\)" nil t)
(setq l (length (match-string 1)))
(if (null base)
(setq base l)
(if (< l base)
(throw 'done t)))
(when (<= l max-depth)
(setq contents (cons (cons l (match-string-no-properties 2))
contents))
(goto-char (match-beginning 2))
(muse-html-insert-anchor (concat "sec" (int-to-string index)))
(delete-backward-char 1)
(setq index (1+ index))))))
(setq index 1 contents (reverse contents))
(let ((depth 1) (sub-open 0) (p (point)))
(insert "<div class=\"mulu\">
<h6 class=\"mulu\">Contents</h6>\n")
(insert "<dl class=\"contents\">\n")
(while contents
(insert "<dt class=\"contents\">\n")
(insert "<a href=\"#sec" (int-to-string index) "\">"
(ywb/muse-publish-strip-tags (cdar contents))
"</a>\n")
(setq index (1+ index))
(insert "</dt>\n")
(setq depth (caar contents)
contents (cdr contents))
(if contents
(cond
((< (caar contents) depth)
(let ((idx (caar contents)))
(while (< idx depth)
(insert "</dl>\n</dd>\n")
(setq sub-open (1- sub-open)
idx (1+ idx)))))
((> (caar contents) depth) ; can't jump more than one ahead
(insert "<dd>\n<dl class=\"contents\">\n")
(setq sub-open (1+ sub-open))))))
(while (> sub-open 0)
(insert "</dl>\n</dd>\n")
(setq sub-open (1- sub-open)))
(insert "</dl>\n")
(insert "</div>\n")
(put-text-property p (point) 'read-only t))))

但是好像不用这个函数也可以,因为可以在css文件中设置contents相应的属性,比如说像 flyzhy的网页中的Contents就感觉还不错。我写信问过他,他说是在css文件中设置的。

http://www.flyzhy.org/projects/WebsiteSettings.html

http://www.mwolson.org/projects/EmacsMuse.html

在Muse的NEWS-3.03(我下载的文件NEWS-3.03)中提到了:

Make the Table of Contents CSS easier to customize.
For an example, see examples/mwolson/stylesheets/screen.css.

如果真能实现像薛瑞尼那样的效果,那可真不错,起码省了一个函数。如果你弄明白了,一定要告诉我啊:)
top给每个标题加个top锚
薛瑞尼的网页中每个标题右边都有一个top的锚,如果一个网页很长,当你想回到页首看 contents的时候,这个锚就很有用了。但是薛瑞尼给我的sacha的函数已经不能用了,于是叶文彬就重写了一个,功能完全一样。

;;;_+ insert toplink in html files
(defun ywb/muse-publish-markup-heading ()
(let* ((len (length (match-string 1)))
(start (muse-markup-text
(cond ((= len 1) 'section)
((= len 2) 'subsection)
((= len 3) 'subsubsection)
(t 'section-other))
len))
(end (muse-markup-text
(cond ((= len 1) 'section-end)
((= len 2) 'subsection-end)
((= len 3) 'subsubsection-end)
(t 'section-other-end))
len)))
(delete-region (match-beginning 0) (match-end 0))
(muse-insert-markup start)
(insert
(propertize
"<span class=\"toplink\"><a href=\"#top\">top</a></span>"
'rear-nonsticky '(read-only) 'read-only t))
(end-of-line)
(when end
(muse-insert-markup end))
(muse-publish-section-close len)))
(defalias 'muse-publish-markup-heading 'ywb/muse-publish-markup-heading)

topywb-muse-publish-project
这个函数我没有用,因为我的配置好像不用它就能正常工作,而且项目组织用"目录树"方式,只要在最上层目录上按Cc Cp就能发布所有没有发布的文件,如果Cu Cc Cp的话,就是全部更新了:)叶文彬在这个函数中把源文件放到发布文件目录中的wikisource下的,我是分开的。而且改了改他的函数也没改对:)如果你看懂了,想改一下就试试吧。

;;;_+ publish functions
(defun ywb-muse-publish-project (&optional arg)
(interactive "P")
(let ((dir default-directory)
(published (muse-project-publish (muse-project) arg))
(muse-explicit-link-functions (remove
'ywb-muse-handle-file-link
muse-explicit-link-functions))
cmd)
(when (= (aref published 0) ?A)
(setq default-directory dir)
(setq cmd (concat "psync .*\\.muse$ "
(expand-file-name
(concat (muse-get-keyword :path (car (cddr
(muse-project))))
"/wikisource/"))))
(message cmd)
(shell-command cmd))
(message published)))

topywb-muse-output-file
这个函数在下面几个函数中用到了

* ywb-muse-publish-this-file
* ywb-muse-preview-with-w3m
* ywb-muse-preview-html
* ywb-muse-preview-source

(defun ywb-muse-output-file ()
"Get output file name"
(let ((styles (muse-project-applicable-styles buffer-file-name (cddr (muse-project))))
output-dir)
(while (and styles
(progn
(setq output-dir (muse-style-element :path (car styles)))
(not (file-exists-p output-dir))))
(setq styles (cdr styles)))
(when output-dir
(muse-publish-output-file
buffer-file-name
output-dir
"html"))))

topywb-muse-publish-this-file
Muse自带的muse-publish-this-file有个Bug,看stid的说明:

muse 中有一个比较不爽的地方,就是单独发布一个文件时,不会发布到指定的项目发布目录中,而用 C-c C-p 发布整个项目就没问题,这是一个 bug。
muse 的BugTracker系统上已经有人提过了,相信不久的将来会有改进。

叶文彬自己定义的发布正在编辑的文件的一个函数,有两个。

其实这不是Bug,只是作者写这个函数的意思被大家误解了吧。我现在用的这个Muse 版本1加上我的配置能自动处理了,不是修复了这个"Bug",而是换了一种方案。如果你装了我装的这个新版本,再按C-c C-h看看:)

C-c C-t muse-project-publish-this-file
C-c C-S-t muse-publish-this-file

如果你用的时候觉得这个"Bug"在你装的Muse的版本上还存在的话,可以试试这两个函数。

(defun ywb-muse-publish-this-file (&optional arg)
"Publish current file to html"
(interactive)
(save-buffer)
(let ((path (muse-get-keyword :path (nth 2 (muse-project)))))
(muse-publish-this-file "xhtml" path current-prefix-arg)))

(defun ywb-muse-publish-this-file (&optional arg)
"Publish current file to html"
(interactive)
(save-buffer)
(let* ((path (file-name-directory (ywb-muse-output-file)))
(muse-explicit-link-functions (remove 'ywb-muse-handle-file-link muse-explicit-link-functions))
(source-path (concat path "/wikisource/")))
(unless (file-exists-p source-path)
(message "Creating wiki source directory %s" source-path)
(make-directory source-path t))
(copy-file buffer-file-name source-path t)
(muse-project-publish-file buffer-file-name (cddr muse-current-project) current-prefix-arg)))

topywb-muse-generate-index
原来生成 index 的方法是在 Wiki Index.muse 里写上:

<lisp>(muse-index-as-string t t)</lisp>

叶文彬写了一个函数,可以使生成的 index 是网页的 title,只要在 Wiki Index.muse 中加上这一句:

<lisp>(ywb-muse-generate-index)</lisp>

也可以传递参数生成多个 project 的目录。例如:

<lisp>(ywb-muse-generate-index '("Debian" "Emacs" "Muse" "GNU"))</lisp>

;;;###autoload
(defun ywb-muse-generate-index (&optional project-list)
"Generate the index of all wikifile except the file in the\"website\" project"
(unless project-list
(setq project-list (list (car (muse-project)))))
(let (project-files title)
(muse-with-temp-buffer
(dolist (project project-list)
(setq project-files (muse-project-file-alist project))
(progn
(insert "* " project "\n"))
(dolist (file project-files)
(unless (or (equal (car file) "index")
(equal (car file) "WikiIndex"))
(insert " - [[" project "#" (car file) "]["
(save-excursion
(set-buffer (generate-new-buffer "*index*"))
(insert-file-contents (cdr file))
(goto-char (point-min))
(setq title
(if (re-search-forward "^#title" nil t)
(buffer-substring (point) (line-end-position))
(car file)))
(kill-buffer (current-buffer))
title)
"]]\n")))
(insert "\n"))
(buffer-string))))

topywb-muse-preview-with-w3m

;;;;_+ preview commands
(defun ywb-muse-preview-with-w3m ()
"Preview the html file"
(interactive)
; (ywb-muse-publish-this-file)
(muse-project-publish-this-file)
(let ((file (ywb-muse-output-file)))
(w3m-goto-url (if (string-match "^[a-zA-Z]:" file)
(ywb-convert-to-cygwin-path file)
(concat "file://" file)))))

topywb-muse-preview-html

(defun ywb-muse-preview-html ()
"Preview the html file"
(interactive)
; (ywb-muse-publish-this-file)
(muse-project-publish-this-file)
(browse-url (ywb-muse-output-file)))

topywb-muse-preview-source

(defun ywb-muse-preview-source ()
"Find the html file"
(interactive)
; (ywb-muse-publish-this-file)
(muse-project-publish-this-file)
(find-file (ywb-muse-output-file)))

top3.02.90 版中的一些问题
叶文彬对3.02.90版Muse中的一些问题的处理。我现在的版本没有测试过,不知道有没有这些问题,供你参考。

* 1. 图片可以自己定义处理路径的函数,但是 muse-colors-insert-image 函数中将 link 转换成绝对路径了,所以其它定义的函数仍然无效。其它文件链接仍然没有一个选项能将路径修改为发布的目录。
* 2. latex2png 中使用 (cd "/tmp"),但是不同平台下的 tmp 目录不同。

top解决方法

* 1. 将 muse-colors-insert-image 中的第一行注释:

;; (setq link (expand-file-name link))

我觉得最好不要一直显示图像,可以用命令 muse-colors-toggle-inline-images 来切换图像的显示。如果想文件的链接是相对于发布目录的路径,可以增加下面的函数:

(defun ywb-muse-handle-file-link (&optional string) ;见上面

* 2. 修改 latex2png 函数:

(defun latex2png (math prefix preamble)
"Convert the MATH code into a png with PREFIX."
(unless preamble
(setq preamble ""))
(let* ((tmppath (cond ((boundp 'temporary-file-directory)
temporary-file-directory)
((fboundp 'temp-directory)
(temp-directory))))
(texfile (expand-file-name
(concat prefix "_" (format "%d" (abs (sxhash math))))
tmppath))
(oldcddir default-directory))
(with-temp-file (concat texfile ".tex")
(insert (concat "\\documentclass{article}
\\usepackage{fullpage}
\\usepackage{amssymb}
\\usepackage[usenames]{color}
\\usepackage{amsmath}
\\usepackage{latexsym}
\\usepackage[mathscr]{eucal}\n" preamble
"\n\\pagestyle{empty}
\\begin{document}"
"{"
math
"}\n"
"\n\\end{document}\n\n")))
(cd tmppath)
(call-process "latex" nil nil nil texfile)
(if (file-exists-p (concat texfile ".dvi"))
(progn
(shell-command-to-string
(concat "dvipng " texfile ".dvi -E "
" -fg " latex2png-fg
" -bg " latex2png-bg " -T tight"
" -x " (format "%s" (* latex2png-scale-factor 1000))
" -y " (format "%s" (* latex2png-scale-factor 1000))
" -o " texfile ".png"))
(if (file-exists-p (concat texfile ".png"))
(progn
(delete-file (concat texfile ".dvi"))
(delete-file (concat texfile ".tex"))
(delete-file (concat texfile ".aux"))
(delete-file (concat texfile ".log"))
(cd oldcddir)
(concat texfile ".png"))
(message "Failed to create png file")))
(message (concat "Failed to create dvi file " texfile)))))

* 3. redefine muse-colors-toggle-inline-images

;;;;_+ redefine of function
(defun muse-colors-insert-image (link beg end invis-props)
"Create an image using create-image or make-glyph and insert it
in place of an image link defined by BEG and END."
;; (setq link (expand-file-name link))
(let ((image-file (cond
((eq muse-colors-inline-image-method 'default-directory)
link)
((functionp muse-colors-inline-image-method)
(funcall muse-colors-inline-image-method link))))
glyph)
(when (stringp image-file)
(if (fboundp 'create-image)
;; use create-image and display property
(add-text-properties beg end
(list 'display (create-image image-file)))
;; use make-glyph and invisible property
(and (setq glyph (muse-make-file-glyph image-file))
(progn
(add-text-properties beg end invis-props)
(add-text-properties beg end (list
'end-glyph glyph
'help-echo link))))))))

top环境变量设置

;;;;_+ variable setting
(add-to-list 'magic-mode-alist
'("#title " . muse-mode))
(when (featurep 'tp-muse-highlight)
(tp-muse-html-syntax-highlight-tag "sqlexample" 'sql-mode)
(tp-muse-html-syntax-highlight-tag "perlexample" 'cperl-mode)
(tp-muse-html-syntax-highlight-tag "javaexample" 'java-mode))

(custom-set-variables
;;;; If you don't want to use any extension at all,
;;;; and want Muse to autodetect project files based on their location,
;;;; then add the following to your Muse settings file.
'(muse-file-extension nil)
'(muse-mode-auto-p t)
;;;; If you don't want to use .muse, you can customize
;;;; the extension by setting the value of muse-file-extension.
'(muse-file-extension "muse")
;;;; The content type used for the HTML <meta> tag.
;;;; If you are striving for XHTML 1.1 compliance,
;;;; you may want to change this to "application/xhtml+xml".
; (setq muse-html-meta-content-type "text/html; charset=utf-8")
;;;; The charset to append to the HTML <meta> tag.
;;;; If set to the symbol 'detect, use muse-html-encoding-map
;;;; to try and determine the HTML charset from emacs's coding.
;;;; If set to a string, this string will be used to force a
;;;; particular charset.
'(muse-html-meta-content-encoding (quote utf-8))
;;;; The default HTML meta charset to use if no translation
;;;; is found in muse-html-encoding-map.
'(muse-html-charset-default "utf-8")

;;;; The default Emacs buffer encoding to use in published files.
;;;; This will be used if no special characters are found.
'(muse-html-encoding-default (quote utf-8))

;;;; An alist mapping emacs coding systems to appropriate HTML
;;;; charsets. Use the base name of the coding system
;;;; (i.e. without the -unix).
'(muse-html-encoding-map "utf8")
'(muse-colors-autogen-headings (quote outline))
'(muse-colors-inline-image-method (quote muse-colors-use-publishing-directory))
'(muse-html-meta-content-encoding (quote utf-8))

'(muse-html-meta-content-type "text/xhtml; charset=utf-8")
'(muse-mode-hook (quote (flyspell-mode footnote-mode)))
'(muse-publish-comments-p t)
'(muse-publish-desc-transforms (quote (muse-wiki-publish-pretty-title muse-wiki-publish-pretty-interwiki)))
'(muse-html-markup-functions (quote ((anchor . muse-html-markup-anchor) (table . muse-html-markup-table) (footnote . muse-html-markup-footnote))))
'(muse-table-line-regexp "^|?[[:blank:]]*\\(?:[^|\n]+\\||\\)[[:blank:]-]+\\([|+]+\\)\\(?:[[:blank:]-]+\\|$\\)[^|\n].*")
'(muse-mode-highlight-p t)
'(muse-wiki-ignore-bare-project-names t)
'(muse-colors-evaluate-lisp-tags nil)
;'(muse-html-style-sheet "<link rel=\"stylesheet\" type=\"text/css\" charset=\"utf-8\" media=\"all\" href=\"../common/stylesheets/core.css\" />")
;'(muse-xhtml-style-sheet "<link rel=\"stylesheet\" type=\"text/css\" charset=\"utf-8\" media=\"all\" href=\"../common/stylesheets/core.css\" />")
'(muse-wiki-publish-small-title-words (quote ("the" "and" "at" "on" "of" "for" "in" "an" "a" "page" "anime"))))

topPlanner抄来的配置

;;;_. planner
(require 'planner nil t)
(require 'planner-id nil t)
(when (featurep 'planner)
(global-set-key (kbd "<f9> t") 'planner-create-task-from-buffer)
(global-set-key (kbd "<f9> c") 'planner-create-task)
(global-set-key (kbd "<f9> <f9>") 'plan)
(require 'remember-planner nil t)
(when (featurep 'remember-planner)
(setq remember-annotation-functions planner-annotation-functions)
(setq remember-handler-functions '(remember-planner-append))))

(autoload 'remember "remember" nil t)
(autoload 'remember-region "remember" nil t)
(global-set-key (kbd "<f9> r") 'remember)
(global-set-key (kbd "<f9> s") 'remember-region)
(global-set-key (kbd "<f9> d") 'planner-diary-add-entry)

(require 'planner-diary nil t)
(when (featurep 'planner-diary)
(defun planner-diary-add-entry (date time text)
"Prompt for a diary entry to add to `diary-file'. Will run
planner-annotations to make hyper links"
(interactive (list (planner-read-date)
(read-string "Time: ")
(read-string "Diary entry: ")))
(save-excursion
(save-window-excursion
(make-diary-entry
(concat
(let ((cal-date (planner-filename-to-calendar-date date)))
(if european-calendar-style
(format "%d/%d/%d"
(elt cal-date 1)
(elt cal-date 0)
(elt cal-date 2))
(format "%d/%d/%d"
(elt cal-date 0)
(elt cal-date 1)
(elt cal-date 2))))
" " time " " text " "
(run-hook-with-args-until-success
'planner-annotation-functions))))))
(setq planner-diary-use-diary t)
(planner-insinuate-diary)
(planner-insinuate-calendar)
(setq planner-diary-number-of-days 7)
(setq planner-diary-number-of-diary-entries 7)
(setq planner-diary-file diary-file))

top快捷键设置

(setq muse-mode-hook
(lambda ()
(footnote-mode)
(auto-fill-mode 1)
(modify-syntax-entry ?> ")" muse-mode-syntax-table)
(modify-syntax-entry ?< "(" muse-mode-syntax-table)
(define-key muse-mode-map (kbd "C-c /") 'sgml-close-tag)
(define-key muse-mode-map (kbd "C-c t") 'sgml-tag)
; (define-key muse-mode-map (kbd "C-c C-t") 'ywb-muse-publish-this-file)
; (define-key muse-mode-map (kbd "C-c C-p") 'ywb-muse-publish-project)
(define-key muse-mode-map (kbd "C-c C-c") 'ywb-muse-preview-source)
(define-key muse-mode-map (kbd "C-c C-j") 'ywb-muse-preview-html)
(define-key muse-mode-map (kbd "C-c C-m") 'ywb-muse-preview-with-w3m)
(define-key muse-mode-map (kbd "<C-return>") 'ywb-html-insert-newline)
(define-key muse-mode-map (kbd "M-RET") 'ywb-insert-item)
))
;;Local variables:
;;allout-layout: (0 : -1 -1 0)
;;End:

top相关链接
topMuse相关
Muse-el BugTracker

http://blog.gmane.org/gmane.emacs.muse.general

Michael Olson—http://www.mwolson.org/projects/EmacsMuse.html

stid—http://learn.tsinghua.edu.cn:8080/98...macs-muse.html

flyzhy—http://www.flyzhy.org/projects/WebsiteSettings.html

ShiXin—http://www.xshi.org/notes/WebPage.html

Gunnar Wrobel—http://gunnarwrobel.de/wiki/EmacsMuseMode.html

Sun Yongke—http://cisd-ftp.swfc.edu.cn/~syk/WebWiki/muse.html

pluskid—http://blog.donews.com/pluskid/archi...06/858197.aspx 他写的用 stardict的sdcv版在emacs里查单词的插件很不错。

http://people.ku.edu/~yjli/dk/EmacsMuse.html

http://ryang.68ab.com/notes_tips.html#top

邢兆鹏—http://www.mysmu.edu/me2005/zhaopeng...g/journal.html 我网页上那个 Google是抄他的,嘿嘿:)
topEmacs Wiki相关

王垠—http://learn.tsinghua.edu.cn:8080/20...wiki/WiKi.html

LiYu—http://59.77.16.178/html/liyu/webpage/EmacsWikiZh.html LiYu的主页好像域名解析不了直接用ip吧:)

http://sacha.free.net.ph/notebook/wiki/AboutMe.php

http://grid.tsinghua.edu.cn/home/liu...lcomePage.html

http://staff.ustc.edu.cn/~yoyosu/Def...lcomePage.html

http://k.thec.cn/Corsair/WelcomePage.html

http://ann77.stu.cdut.edu.cn/EmacsWikiNote.html

http://wwwhomes.uni-bielefeld.de/tli...acs_using.html

http://www.iamstone.net/publish/note/Emacs.html

http://people.ku.edu/~yjli/dk/Emacswiki.html

--
一步一步教你从互联网赚钱 http://www.zqzn.com/index.asp?rid=key480769
投资理财 http://li-cai.blogspot.com/