About neohope

一直在努力,还没想过要放弃...

修改Thunderbird Mbox文件,找回丢失邮件

今天周六,起了个早,吃了早饭,沏上茶,一边洗衣服,一遍happy的看邮件。
邮件积攒的太多,于是操作就太快,结果,不知道为什么,一片邮件就消失了。

重要提示:
以下所有操作的前提是:进行完全备份

于是,尝试了重建所在文件夹的.msf索引文件,有两种方式:
1、在文件夹上,右击-》属性-》修复文件夹
2、关闭thunderbird,到邮箱路径下,删掉文件夹的.msf文件,重新打开Thunderbird
然后发现,只找回一部分邮件来。

这可不行,好多邮件很重要,于是,进行了大还原:
关闭Thunderbird,将global-messages-db.sqlite命名为global-messages-db.sqlite.bak,重启Thunderbird。
还是不行~~
哭的心都有了

好吧,找工具~~
尝试了ZMail和Advanced Media Recovery,测试证明,根本不好用~~

那只好找资料,自己开搞了。
Thunderbird的一个最底层邮件文件夹,由两部分组成,
没有后缀的MBox文件,和有后缀的.msf索引文件。

MBox就是邮件和附件的全部了,经过摸索,发现有以下规律
1、MBox可以用靠谱的文本编辑工具进行编辑,用notepad的同学们,您就省省吧
2、每一封邮件都是一段MIME格式的文本,每封邮件以如下格式开始,直到下一个”From – “结束

From - Thu Dec 19 01:26:18 2013
X-Account-Key: account4
X-UIDL: ZC0418-TJAs6xVgg1PigBtJ_pc_a3c
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
X-Mozilla-Keys:                                                                                 
X-QQ-SSF: 00410000000000F0
X-QQ-BUSINESS-ORIGIN: 2
X-Originating-IP: 112.65.5.74
X-QQ-STYLE: 
X-QQ-mid: bizmail35t1387361723t6111701
From: "=?utf-8?B?5pyx6I6J6Imz?=" <xxx@xxx.com>
To: "=?utf-8?B?6auY5pmX?=" <xxx@xxx.com>

3、邮件根据编码不同,主要有gb2312,utf-8和BASE64编码三种
4、附件以MIME方式存储在邮件下面,如:

MIME-Version: 1.0
Content-Type: multipart/related;
	boundary="----=_NextPart_000_0007_01CE78E0.0A87C340"
...

5、两份邮件之间,没有关联关系,可以随便修改顺序,可以随便剪切复制粘贴,但要保证每一封邮件的完整性
6、邮件的状态,由以下两个标志位指定

module Mbox
  #X-Mozilla-Status
  #Message has been read.
  MSG_FLAG_READ=0x0001
  #A reply has been successfully sent.
  MSG_FLAG_REPLIED=0x0002
  #The user has flagged this message.
  MSG_FLAG_MARKED=0x0004
  #Already gone (when folder not compacted). Since actually removing a message from a folder is a semi-expensive operation, we tend to delay it; messages with this bit set will be removed the next time folder compaction is done. Once this bit is set, it never gets un-set.
  MSG_FLAG_EXPUNGED=0x0008
  #Whether subject has “Re:” on the front. The folder summary uniquifies all of the strings in it, and to help this, any string which begins with “Re:” has that stripped first. This bit is then set, so that when presenting the message, we know to put it back (since the “Re:” is not itself stored in the file).
  MSG_FLAG_HAS_RE=0x0010
  #Whether the children of this sub-thread are folded in the display.
  MSG_FLAG_ELIDED=0x0020
  #DB has offline news or imap article.
  MSG_FLAG_OFFLINE=0x0080
  #If set, this thread is watched.
  MSG_FLAG_WATCHED=0x0100
  #If set, then this message's sender has been authenticated when sending this msg. This means the POP3 server gave a positive answer to the XSENDER command. Since this command is no standard and only known by few servers, this flag is unmeaning in most cases.
  MSG_FLAG_SENDER_AUTHED=0x0200
  #If set, then this message's body contains not the whole message, and a link is available in the message to download the rest of it from the POP server. This can be only a few lines of the message (in case of size restriction for the download of messages) or nothing at all (in case of “Fetch headers only”)
  MSG_FLAG_PARTIAL=0x0400
  #If set, this message is queued for delivery. This only ever gets set on messages in the queue folder, but is used to protect against the case of other messages having made their way in there somehow – if some other program put a message in the queue, it won't be delivered later!
  MSG_FLAG_QUEUED=0x0800
  #This message has been forwarded.
  MSG_FLAG_FORWARDED=0x1000
  #These are used to remember the message priority in interal status flags.
  MSG_FLAG_PRIORITIES=0xE000

  
  #X-Mozilla-Status2
  #This message is new since the last time the folder was closed.
  MSG_FLAG2_NEW=0x00010000
  #If set, this thread is ignored.
  MSG_FLAG2_IGNORED=0x00040000
  #If set, this message is marked as deleted on the server. This only applies to messages on IMAP servers.
  MSG_FLAG2_IMAP_DELETED=0x00200000
  #This message required to send a MDN (Message Disposition Notification) to the sender of the message. For information about MDN see Wikipedia:Return receipt.
  MSG_FLAG2_MDN_REPORT_NEEDED=0x00400000
  #An MDN report message has been sent for this message. No more MDN report should be sent to the sender.
  MSG_FLAG2_MDN_REPORT_SENT=0x00800000
  #If set, this message is a template.
  MSG_FLAG2_TEMPLATE=0x01000000
  #These are used to store the message label.
  #label value
  #1 0x02000000
  #2 0x04000000
  #3 0x06000000
  #4 0x08000000
  #5 0x0A000000
  #6 0x0C000000
  #7 0x0E000000
  MSG_FLAG2_LABELS=0x0E000000
  #If set, this message has files attached to it.
  MSG_FLAG2_ATTACHMENT=0x10000000 
end

这样就好办了,写了个程序,查找每个mbox文件内的每个EMail,查看状态,找出状态错误的邮件:
PS:Ruby加起来学了没几天,哈哈哈

#!/usr/bin/ruby

class EnumFiles
  def enumFiles(folderPath)
    #枚举文件
    files = Dir.glob(folderPath+"*")
    return files
  end
  
  def enumFilesAll(folderPath)
    #枚举文件
    files = Dir.glob(folderPath+"**/*")
    return files
  end
end
#!/usr/bin/ruby

class ReadMbox
  def readLine(filePath)
    if File.exist?(filePath)
      f = File.open(filePath,"r+")
      lines=f.readlines
      return lines
    else
      puts(filePath + " does not exist")
    end
  end
  
  def readMsgNum(filePath,rootPath)
    msgNum=0
    msgErr=0
    bError=false
    
    if File.exist?(filePath)
          f = File.open(filePath,"r+")
          f.each{|l|
            if(l[0..6]=="From - ")
              msgNum=msgNum+1
              bError=false
            end
            
            if(l[0..17]=="X-Mozilla-Status: ") && (!bError)
              flag = l[18..21].to_i(16)
              if(flag & 0x0008 > 0)
                puts("]>"+l)
                msgErr=msgErr+1
                bError=true
              end
            end
      
            if(l[0..18]=="X-Mozilla-Status2: ") && (!bError)
              flag2 = l[19..26].to_i(16)
              if(flag2 & 0x00040000 > 0)
                puts("]>"+l)
                msgErr=msgErr+1
                bError=true
              end
            end
          }
    end
          
    puts(filePath.gsub(rootPath,"")+" EmailNum=\t"+msgNum.to_s()+"\terrNum=\t"+msgErr.to_s())
  end
end
#!/usr/bin/ruby

require "./EnumFiles.rb"
require "./ReadMbox.rb"

rootPath="PAHT/TO/MAIL/

files = EnumFiles.new().enumFilesAll(rootPath)
#puts files

mbox = ReadMbox.new()

files.each do |f|
  if(!File.directory?(f)) && (!(File.extname(f).length>0))
    mbox.readMsgNum(f,rootPath)
  end
end

最后,找到文件,发现并不是很多只有5个,就懒得写程序了,手动剪切到回收站,将标志位置为正常,刷新回收站索引,然后一切就太平啦

X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000

后记:
其实Thunderbird在删除邮件时(从回收站删除),为提高效率,并不一定会真的将邮件删掉,而很可能只是打上一个标记。

这样,其实只要用一个靠谱的编辑器,比如VIM、PSPad等,就可以很方便的定位到你需要的邮件,然后就可以进行备份和还原啦。

参考:
全局还原索引文件
官方推荐的编辑工具列表
标志位说明
标志位源码

jQuery的AJAX示例

	var textRet;
	var textJson;
	var textUrl;
	var timeoutMS;
	$.ajax( {
		type : 'POST',
		data : textJson,
		url : textUrl,
		dataType : 'json',
		timeout : timeoutMS,
		success : function(jsonRet) {
			//do something here
			textRet=...;
		},
		error:function(jqXHR, textStatus, errorThrown) {
			if(textStatus==='error') {
				//do something here
				textRet=...;
			}
			if(textStatus==='timeout') {
				//do something here
				textRet=...;
			}
                }
	});

Tomcat强制使用HTTPS

配置好Tomcat的SSL后,强制使用HTTPS方法如下:

1、全局强制HTTPS
修改%tomcat_home%\conf\web.xml,在文件底部,后面加上这样一段:

    <login-config>  
        <!-- Authorization setting for SSL -->  
        <auth-method>CLIENT-CERT</auth-method>  
        <realm-name>Client Cert Users-only Area</realm-name>  
    </login-config>  
    <security-constraint>  
        <!-- Authorization setting for SSL -->  
        <web-resource-collection >  
            <web-resource-name >SSL</web-resource-name>  
            <url-pattern>/*</url-pattern>  
        </web-resource-collection>  
        <user-data-constraint>  
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
        </user-data-constraint>  
    </security-constraint>  

2、某个webapp强制使用HTTPS
编辑该webapp的web.xml文件,增加以下内容:

	<security-constraint>
	    <web-resource-collection>
	        <web-resource-name>securedapp</web-resource-name>
	        <url-pattern>/*</url-pattern>
	    </web-resource-collection>
	    <user-data-constraint>
	        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
	    </user-data-constraint>
	</security-constraint>

关闭 SSL,只需要将CONFIDENTIAL改为NONE即可。

ANT出现“命令语法不正确”

昨天用ant编译代码时,报了一个很诡异的错误:
“命令语法不正确。”

分析了半天发现,原来是我在bat文件中多了””,悲剧啊。

set JAVA_HOME="D:\JavaJDK\jdk1.6.0_34_x86"
set ANT_HOME="D:\JavaTools\apache-ant-1.9.0"
set PATH=%ANT_HOME%\bin;%JAVA_HOME%\bin;%PATH%

将引号去掉就好了

set JAVA_HOME=D:\JavaJDK\jdk1.6.0_34_x86
set ANT_HOME=D:\JavaTools\apache-ant-1.9.0
set PATH=%ANT_HOME%\bin;%JAVA_HOME%\bin;%PATH%

开源IM软件

近期研究了下开源的IM软件:

软件名 源码语言 开源协议 网站地址
PIDGIN c,gcc/MinGW,gtk+ GPL v2 http://www.pidgin.im/
Instantbird c+MozillaBuild MPL1.1 https://wiki.instantbird.org/Main_Page
RetroShare c,cpp,QT MPL1.1 http://retroshare.sourceforge.net/downloads.html
OneTeam JS, C++ XPCOM, Mozilla/XUL MPL1.1 https://github.com/processone/oneteam
Coccinella TCL GPLv3 http://coccinella.im/
OpenFire+Spark java GPLv2 http://www.igniterealtime.org/downloads/index.jsp
iQQ java LGPL https://github.com/im-qq
ipmsg(飞鸽传书) vc no control http://ipmsg.org/
ipmsg .Net C# GPLv3 http://code.google.com/p/ipmessagernet/
freeeim(飞秋) vc no control http://freeeim.com/

VC fix .pch file missing

表现:

Error   1   fatal error C1083: Cannot open precompiled header file: 'Debug\????.pch': No such file or directory

解决方法:
1、保证stdafx.h及stdafx.cpp在项目的最顶层,stdafx.h用于保存需要的头文件,stdafx.cpp中只有对stdafx.h的引用;
2、在VS中,右击需要修改的工程,选择”Properties”;
3、在左上角,选择“ All Configurations”;
4、在左边,找到“C/C++”,并定位到“Precompiled Headers”;
5、将选项Precompiled Header修改为: “Use (/Yu)”;
6、将选项“Precompiled Header File”修改为:“stdafx.h”;
7、保存设置;
8、保证#include “stdafx.h”为所有需要预编译的cpp文件的第一行;
9、VS中,右击stdafx.cpp,选择”Properties”;
10、在左上角,选择“ All Configurations”;
11、将选项Precompiled Header修改为: “Create (/Yc).”;
12、保存设置,重新编译。

第一次拆iPhone4(后记)

过了两周,液晶的花屏慢慢好了,感觉相当不错。

但最近发下,液晶花屏的地方,有一道比较明显的折痕,锁屏界面看不出来,解锁界面十分明显。

估计花屏就是它的原因吧。

🙂

PS:
今天早上又摔了,直接关机了,开不开。
插上数据线后,又可以用了,我可怜的iphone4啊。

JavaScript checking for null vs. undefined

JS中undefined表示变量没有定义或从来没有赋值,而null是空对象,是有值的。
例如:

var a;
alert(typeof a);
//"undefined"

a = null;
alert(typeof null);
//"object"

JS中==比较为弱类型比较,JS会自动进行类型转换,然后返回值的比较结果。
而===为强类型比较,即必须类型与值同时相同,才会相等。
例如:

alert(0 == "0");
//true

alert(0==="0");
//false

alert(undefined == null);
//true

alert(undefined === null);
//false

判断变量为null:

if (a === null)
// or
if (a == null)

第一种方法,当a为undefined时返回false,
第二种方法,当a为undefined时返回true。

判断变量为undefined:

if (typeof a === "undefined")
// or
if (a === undefined)
// or
if (a == undefined)

第一、二种方法,当a为null时返回false,
第三种方法,当a为null时返回true。

还有一种使用falsey进行检查的方法:

if (!a) {
    // `a` is falsey, which includes `undefined` and `null`
    // (and `""`, and `0`, and `false`)
}

大部分翻译自stackoverflow:
JavaScript checking for null vs. undefined and difference between == and ===

GitHub03SSH授权

用低版本的github做上传的时候,会有提示

Permission denied (publickey). 

最简单的方法,就是安装新版本的GitHub。

如果你实在不愿意升级,那可以用以下步骤来进行:

#1、测试ssh,会提示Permission denied (publickey). 
ssh -T git@github.com 
#2、生成新的授权文件,如果你没有改过配置,那文件名为github_rsa,密码保持为空即可
ssh-keygen -t rsa -C "neohope@yahoo.com"
#3、查看新的key
ssh-add -l
#4、登录GitHub网站,到管理SSH Keys的地方,上传public key
#~/.ssh/github_rsa.pub
#5、测试ssh,会提示成功
ssh -T git@github.com 

搞定!

Prolog101(08)

列表:
放在用方括号中的一组项目的集合,各项目之间使用逗号分割。

空表:
没有项目的列表,用[]表示。

表头与表尾:
[X|Y]可以与任意的列表匹配,匹配成功后,X绑定为列表的第一个项目的值,我们称之为表头(head)。
而Y则绑定为剩下的列表,我们称之为表尾(tail)。
表尾(tail)一定是列表,而表头(head)则是一个项目,该项目可以是表,也可以是其他的任何数据结构。
看下这个例子就清楚了:

1 ?- [a|[b,c,d]] = [a,b,c,d]. 
true.

2 ?- [a|b,c,d] = [a,b,c,d].
ERROR: Syntax error: Unexpected comma or bar in rest of list
...

3 ?- [H|T] = [a]. 
H = a,
T = [].
 
4 ?- [H|T] = [a,b,c,d]. 
H = a,
T = [b, c, d].

5 ?- [H|T] = [a,[b,c,d]]. 
H = a,
T = [[b, c, d]].

6 ?- [H|T] = [].
false.

7 ?- [A,B|T] = [a,b,c,d].
A = a,
B = b,
T = [c, d].

8 ?- [a|[b|[c|[d|[]]]]] = [a,b,c,d].
true.

检查数据是否存在:

1 ?- member(a, [a,b,c]). 
true .

2 ?- member(d, [a,b,c]). 
false.

3 ?- member(d, [a,b,c,[d],e]). 
false.

4 ?- member([d], [a,b,c,[d],e]).
true .

5 ?- member(X, [a,b,c]). 
X = a ;
X = b ;
X = c.

追加

1 ?- append([a,b,c],[d,e,f],X).
X = [a, b, c, d, e, f].

2 ?- append([],[d,e,f],X).
X = [d, e, f].

3 ?- append([a,b],Y,[a,b,c,d]).
Y = [c, d].

4?- append(X,Y,[a,b,c]).
X = [],
Y = [a, b, c] ;
X = [a],
Y = [b, c] ;
X = [a, b],
Y = [c] ;
X = [a, b, c],
Y = [] ;

删除

1 ?- delete([a,b,c,d,e], c, X).
X = [a, b, d, e]