most geek wordpress theme
Have a try if you like unix.
yichao firstname, zeaster nickname, zhang lastname
Have a try if you like unix.
Labels: blog
These days, I've been developing an application that reads and writes entries from/into Android Contacts.
Everything goes fine until I need to insert email entry into Android Contact by Contact Content Provider API.
This is how to insert a people or phone entry into contact (people, phones table):
getContentProvider().insert(People.CONTENT_URI, values);
getContentProvider().insert(Phones.CONTENT_URI, values);
That's fine according to
http://code.google.com/android/devel/data/contentproviders.html
However when I insert an email entry into contact (in contact_methods table) using:
ContentURI uri = getContentProvider().insert(ContactMethods.CONTENT_URI, values);
It just returns null, nothing inserted, and nothing shows up on logcat.
Why? the link above says it should be fine!
To find the answer, I post a thread in Google Group:
http://groups.google.com/group/android-developers/browse_thread/thread/9ed4ff7fc1338b7c
However no response.
then I have been diving into build-in Contacts Application for 2 days to find how Google used their own api.
Luckily, I got the key.
see details on my another post:
http://zeaster.blogspot.com/2007/11/how-to-decompile-dex-file-on-android_28.html
You should insert an email like this:
ContentURI uri = People.CONTENT_URI.addId(user_id).addPath("contact_methods");
ContentValues values = ...
uri = getContentResolver().insert(uri, values);
why? I guess Google should provide one same way to insert content.
That's the main inconvenience.
I guess what's even worse is Google does not provide enough docs or log warnings for this tip.
Here are the others:
2.
when insert an email for a not-created-yet user id, It's still inserted successfully.
when the user id created in the future, the user would have the email address.
I guess Google should prevent this happen.
Actually many checks Google need to do.That's really a beta SDK.
3.
The content provider API is not Object-Oriented enough.
I feel it tedious to use.
4.
Maybe this is greedy.
I hope there is API to manipulate database that's similar to ActiveRecord for Rails.
Maybe I will implement one like that if time permits.
Lucky to see the Google Android build-in Contacts is also developed by Android SDK.
This article will take it for example and discuss these How-To's:
1 How to find the Contacts App file on Google Android
2 How to find the Contacts App's classes.dex on Google Android
3 How to dump the Contacts App's classes
4 How to decompile the dumped file
{
Actually, I think the Contacts Content Provider that Google provides has some inconvenience to use.
And I will post another blog to list what's inconvenience and request some improvement from Google.
The blog link is here:
http://zeaster.blogspot.com/2007/11/inconvenienced-when-using-contact.html
}
1 How to find the Contacts App on Google Android
Using adb tool
$ adb shell
# cd /system/app
cd /system/app
# ls
ls
-rw-r--r-- root root 25519 2007-11-14 20:40 ContactsProvider.apk
-rw-r--r-- root root 7544 2007-11-14 20:40 GoogleAppsProvider.apk
-rw-r--r-- root root 16198 2007-11-14 20:40 ImProvider.apk
-rw-r--r-- root root 20308 2007-11-14 20:40 MediaProvider.apk
-rw-r--r-- root root 21272 2007-11-14 20:40 TelephonyProvider.apk
-rw-r--r-- root root 11809 2007-11-14 20:40 SettingsProvider.apk
-rw-r--r-- root root 418688 2007-11-14 20:41 Browser.apk
-rw-r--r-- root root 68077 2007-11-14 20:41 Contacts.apk
-rw-r--r-- root root 96287 2007-11-14 20:41 Development.apk
-rw-r--r-- root root 44790 2007-11-14 20:41 GoogleApps.apk
-rw-r--r-- root root 8637 2007-11-14 20:41 Fallback.apk
-rw-r--r-- root root 99431 2007-11-14 20:41 Home.apk
-rw-r--r-- root root 171614 2007-11-14 20:41 Maps.apk
-rw-r--r-- root root 424601 2007-11-14 20:41 Phone.apk
-rw-r--r-- root root 192119 2007-11-14 20:41 XmppService.apk
-rw-r--r-- root root 6614 2007-11-14 20:41 XmppSettings.apk
#
The Contacts.apk is the Contacts App and ContactsProvider.apk is the app that provides the Contact Content Provider for reading and writing "content://contacts/" resources.
we can see many system apps developed by Android Java SDK are put here.
However what is inside *.apk file. Actually it is a .zip file. It is easy to unzip and get the answer.
take Contacts.apk for example, it contains:
META-INF\
res\
AndroidManifest.xml
classes.dex
resources.arsc
The classes.dex file contains all compiled Java code.
2 How to find the Contacts App's classes.dex on Google Android
No need to unzip Contacts App's classes.dex file from Contacts.apk file.
The Dalvik VM has a cached file for us. Go head to find it.
$ adb shell
# cd /data/dalvik-cache
cd /data/dalvik-cache
# ls
ls
-rw-rw-rw- root root 73852 2007-11-27 05:16 system@app@Contacts.apk@classes.dex
-rw-rw-rw- app_0 app_0 64172 2007-11-27 05:17 system@app@ContactsProvider.apk@classes.dex
-rw-rw-rw- root root 15204 2007-11-27 05:17 system@framework@am.jar@classes.dex
-rw-rw-rw- app_3 app_3 3012 2007-11-27 07:33 system@app@Fallback.apk@classes.dex
-rw-rw-rw- root root 7252804 2007-11-27 05:16 system@framework@core.jar@classes.dex
....and many other cached files.
3 How to dump the Contacts App's classes
Unfortunately the classes.dex is not a .jar file. It's Dalvik executable format that is optimized for efficient.
so we can not pull the .class files as .jar format. However Google Android provides a tool named dexdump included in the emulator to dump .dex file. Here is how to use it.
# dexdump
dexdump: no file specified
dexdump: [-f] [-h] dexfile...
-d : disassemble code sections
-f : display summary information from file header
-h : display file header details
-C : decode (demangle) low-level symbol names
-S : compute sizes only
Now we dump the system@app@Contacts.apk@classes.dex and system@app@ContactsProvider.apk@classes.dex.
# dexdump -d -f -h -C system@app@Contacts.apk@classes.dex >> Contacts.apk.dump
# dexdump -d -f -h -C system@app@ContactsProvider.apk@classes.dex >> ContactsProvider.apk.dump
and then pull it out.
# exit
$ adb pull /data/dalvik-cache/Contacts.apk.dump ~/android
$ adb pull /data/dalvik-cache/ContactsProvider.apk.dump ~/android
Now we get the dumped files on ~/android folder.
4 How to decompile the dumped file
.dex file is optimized, so we can not decompile it as normal .class file.
Fortunately the dumped file is a bit readable for me.
As it is too big to analyze all the code, so I just take "how to create a contact" for example.
It's easy to get this info from the dumped file.
It has these classes:
...
Class name : 'com/google/android/contacts/AttachImage'
Class name : 'com/google/android/contacts/ContactEntryAdapter'
Class name : 'com/google/android/contacts/EditContactActivity'
Class name : 'com/google/android/contacts/EditContactActivity$EditEntry'
...
The EditContactActivity class has a private void create() method.
#3 : (in com/google/android/contacts/EditContactActivity)
name : 'create'
type : '()V'
access : 0x0002 (PRIVATE)
So all the code that create a contact is here from the dumped file, my comments inlined:
// private void create()
009b24: |[009b24] com/google/android/contacts/EditContactActivity.create:()V
// ContentValues v9 = new ContentValues();
009b28: 2109 3100 |0000: new-instance v9, android/content/ContentValues // class@0031
009b2c: 6f01 0f00 0900 |0002: invoke-direct {v9}, android/content/ContentValues.
// Entry v12 = this.getCurrentEntry();
009b32: f4fc a800 |0005: +iget-object-quick v12, v15, [obj+00a8]
// int v11 = v12.lines
009b36: f801 1500 0c00 |0007: +invoke-virtual-quick {v12}, [0015] // vtable #0015
009b3c: 0a0b |000a: move-result v11
// int v5 = 0
009b3e: 1205 |000b: const/4 v5, #int 0 // #0
// if v5 >= v11 goto 0046
009b40: 3ab5 3a00 |000c: if-ge v5, v11, 0046 // +003a
// EditEntry v8 = (EditEntry)this.getCurrentEntry();
009b44: f4fc a800 |000e: +iget-object-quick v12, v15, [obj+00a8]
009b48: f802 1a00 5c00 |0010: +invoke-virtual-quick {v12, v5}, [001a] // vtable #001a
009b4e: 0c0c |0013: move-result-object v12
009b50: 07c0 |0014: move-object v0, v12
009b52: 1e00 3d00 |0015: check-cast v0, com/google/android/contacts/EditContactActivity$EditEntry // class@003d
009b56: 0708 |0017: move-object v8, v0
// int v12 = v8.kind // The Instance field kind is defined in its superclass Entry. see details in dumped Entry and EditEntry sections.
009b58: f28c 1400 |0018: +iget-quick v12, v8, [obj+0014]
// int v13 = -3 // PHOTO_KIND = -3 defined in v8's superclass Entry
009b5c: 12dd |001a: const/4 v13, #int -3 // #fd
// if v12 != v13 goto 0020 // a photo entry, goto 0020
009b5e: 38dc 0500 |001b: if-ne v12, v13, 0020 // +0005
// int v5++;
009b62: d805 0501 |001d: add-int/lit8 v5, v5, #int 1 // #01
// goto 000c
009b66: 33ed |001f: goto 000c // -0013
// String v7 = v8.getData();
009b68: f801 0c00 0800 |0020: +invoke-virtual-quick {v8}, [000c] // vtable #000c
009b6e: 0c07 |0023: move-result-object v7
// boolean v12 = TextUtils.isEmpty(v7)
009b70: 7001 4200 0700 |0024: invoke-static {v7}, android/text/TextUtils.isEmpty:(Ljava/lang/CharSequence;)Z // method@0042
009b76: 0a0c |0027: move-result v12
if v12!=false/0 goto 0030
009b78: 3e0c 0800 |0028: if-nez v12, 0030 // +0008
// String v12 = v8.column // The Instance field column is defined in EditEntry. see details in dumped EditEntry section.
009b7c: f48c 2800 |002a: +iget-object-quick v12, v8, [obj+0028]
// v9.put(v12,v7) // v9 is a ContentValues, v12 is the column name, v7 is the value.
009b80: f803 0b00 c907 |002c: +invoke-virtual-quick {v9, v12, v7}, [000b] // vtable #000b
// goto 001d
009b86: 33ee |002f: goto 001d // -0012
// String v12 = v8.column // The Instance field column is defined in EditEntry. see details in dumped EditEntry section.
009b88: f48c 2800 |0030: +iget-object-quick v12, v8, [obj+0028]
// String v13 = "name";
009b8c: 180d 1c00 |0032: const-string v13, "name" // string@001c
// boolean v12 = v12.equals(v13);
009b90: ee02 0300 dc00 |0034: +execute-inline {v12, v13}, java/lang/String.equals:(Ljava/lang/Object;)Z // inline #0003
009b96: 0a0c |0037: move-result v12
// if v12 != false/0, goto 001d
009b98: 3d0c e5ff |0038: if-eqz v12, 001d // -001b
// String v12 = "EditContactActivity"
009b9c: 180c 0100 |003a: const-string v12, "EditContactActivity" // string@0001
// String v13 = "Name is required"
009ba0: 180d 0200 |003c: const-string v13, "Name is required" // string@0002
// Log.e(v12, v13); //log info using android/util/Log
009ba4: 7002 4700 dc00 |003e: invoke-static {v12, v13}, android/util/Log.e:(Ljava/lang/String;Ljava/lang/String;)I // method@0047
009baa: 0a0c |0041: move-result v12
// call this.XXX()
009bac: f801 8400 0f00 |0042: +invoke-virtual-quick {v15}, [0084] // vtable #0084
// return void
009bb2: 0e00 |0045: return-void
// ContentResolver v12 = this.getContentResolver();
009bb4: f4fc a400 |0046: +iget-object-quick v12, v15, [obj+00a4]
// CONTENT_URI v13 = People.CONTENT_URI;
009bb8: 610d 0300 |0048: sget-object v13, android/provider/Contacts$People.CONTENT_URI:Landroid/net/ContentURI; // field@0003
// CONTENT_URI v10 = v12.insert(v13, v9) // CONTENT_URI v10 = getContentResolver().insert(uri, values);
// insert people into contacts
009bbc: f803 1100 dc09 |004a: +invoke-virtual-quick {v12, v13, v9}, [0011] // vtable #0011
009bc2: 0c0a |004d: move-result-object v10
// List v12 = this.mContactEntries
009bc4: f4fc c000 |004e: +iget-object-quick v12, v15, [obj+00c0]
009bc8: 7001 8900 0c00 |0050: invoke-static {v12}, com/google/android/contacts/ContactEntryAdapter.countEntries:(Ljava/util/ArrayList;)I // method@0089
009bce: 0a06 |0053: move-result v6
// int v5 = v11 //contact Entry Count
009bd0: 01b5 |0054: move v5, v11
// if v5 >= v6, goto 009e
009bd2: 3a65 4900 |0055: if-ge v5, v6, 009e // +0049
// List v12 = this.mContactEntries
009bd6: f4fc c000 |0057: +iget-object-quick v12, v15, [obj+00c0]
// EditEntry v8 = (EditEntry) getEntry(v12, v5);
009bda: 7002 8b00 5c00 |0059: invoke-static {v12, v5}, com/google/android/contacts/ContactEntryAdapter.getEntry:(Ljava/util/ArrayList;I)Lcom/google/android/contacts/ContactEntryAdapter$Entry; // method@008b
009be0: 0c0c |005c: move-result-object v12
009be2: 07c0 |005d: move-object v0, v12
009be4: 1e00 3d00 |005e: check-cast v0, com/google/android/contacts/EditContactActivity$EditEntry // class@003d
009be8: 0708 |0060: move-object v8, v0
// int v12 = v8.kind // The Instance field kind is defined in its superclass Entry. see details in dumped Entry and EditEntry sections.
009bea: f28c 1400 |0061: +iget-quick v12, v8, [obj+0014]
// int v13 = -1 // CONTACT_KIND = -1 defined in v8's superclass Entry
009bee: 12fd |0063: const/4 v13, #int -1 // #ff
// if v12 == v13 goto 007e
009bf0: 37dc 1a00 |0064: if-eq v12, v13, 007e // +001a
// v9.clear() // ContentValues.clear()
009bf4: f801 1500 0900 |0066: +invoke-virtual-quick {v9}, [0015] // vtable #0015
// boolean v12 = v8.toValues(v9) // boolean EditEnty.toValues(ContentValues cv)
009bfa: f802 0d00 9800 |0069: +invoke-virtual-quick {v8, v9}, [000d] // vtable #000d
009c00: 0a0c |006c: move-result v12
//if v12 !=false/0, goto 007b
009c02: 3d0c 0e00 |006d: if-eqz v12, 007b // +000e
// ContentResolver v12 = this.getContentResolver();
009c06: f4fc a400 |006f: +iget-object-quick v12, v15, [obj+00a4]
// String v13 = v8.contentDirectory
009c0a: f48d 2c00 |0071: +iget-object-quick v13, v8, [obj+002c]
// v10.addPath(v13);
009c0e: f802 1800 da00 |0073: +invoke-virtual-quick {v10, v13}, [0018] // vtable #0018
009c14: 0c0d |0076: move-result-object v13
// CONTENT_URI v12 = v12.insert(v13, v9) // CONTENT_URI v12 = getContentResolver().insert(uri, values);
009c16: f803 1100 dc09 |0077: +invoke-virtual-quick {v12, v13, v9}, [0011] // vtable #0011
009c1c: 0c0c |007a: move-result-object v12
// int v5++;
009c1e: d805 0501 |007b: add-int/lit8 v5, v5, #int 1 // #01
// goto 0055
009c22: 33d8 |007d: goto 0055 // -0028
// String v7 = v8.getData();
009c24: f801 0c00 0800 |007e: +invoke-virtual-quick {v8}, [000c] // vtable #000c
009c2a: 0c07 |0081: move-result-object v7
// v9.lines
009c2c: f801 1500 0900 |0082: +invoke-virtual-quick {v9}, [0015] // vtable #0015
// boolean v12 = TextUtils.isEmpty(v7)
009c32: 7001 4200 0700 |0085: invoke-static {v7}, android/text/TextUtils.isEmpty:(Ljava/lang/CharSequence;)Z // method@0042
009c38: 0a0c |0088: move-result v12
if v12!=false/0 goto 007b
009c3a: 3e0c f2ff |0089: if-nez v12, 007b // -000e
// String v12 = v8.column // The Instance field column is defined in EditEntry. see details in dumped EditEntry section.
009c3e: f48c 2800 |008b: +iget-object-quick v12, v8, [obj+0028]
// v9.put(v12,v7) // v9 is a ContentValues, v12 is the column name, v7 is the value.
009c42: f803 0b00 c907 |008d: +invoke-virtual-quick {v9, v12, v7}, [000b] // vtable #000b
// ContentResolver v12 = this.getContentResolver();
009c48: f4fc a400 |0090: +iget-object-quick v12, v15, [obj+00a4]
// int v13 = 0
009c4c: 120d |0092: const/4 v13, #int 0 // #0
// int v14 = 0
009c4e: 120e |0093: const/4 v14, #int 0 // #0
009c50: 07c0 |0094: move-object v0, v12
009c52: 07a1 |0095: move-object v1, v10
009c54: 0792 |0096: move-object v2, v9
009c56: 07d3 |0097: move-object v3, v13
009c58: 07e4 |0098: move-object v4, v14
// int v12 = v12.update(v1,v2,v3,v4) // getContentResolver(),update(uri, values, null, null)
// refer to this method, public final int update(ContentURI uri, ContentValues values, String where, String[] selectionArgs)
009c5a: f905 1400 0000 |0099: +invoke-virtual-quick/range {v0, v1, v2, v3, v4}, [0014] // vtable #0014
009c60: 0a0c |009c: move-result v12
// goto 007b
009c62: 33de |009d: goto 007b // -0022
// int v12 = 4
009c64: 124c |009e: const/4 v12, #int 4 // #4
009c66: f5fc c800 |009f: +iput-quick v12, v15, [obj+00c8]
009c6a: f7fa 9000 |00a1: +iput-object-quick v10, v15, [obj+0090]
// int v12 = -1
009c6e: 12fc |00a3: const/4 v12, #int -1 // #ff
009c70: f801 0700 0a00 |00a4: +invoke-virtual-quick {v10}, [0007] // vtable #0007
009c76: 0c0d |00a7: move-result-object v13
009c78: f803 7f00 cf0d |00a8: +invoke-virtual-quick {v15, v12, v13}, [007f] // vtable #007f
// goto 0045
009c7e: 339a |00ab: goto 0045 // -0066
exceptions : (none)
positions : 30
0x0000 line=471
.....
0x00a3 line=515
locals : 10
//the 10 local variables defined here
0x0000 - 0x00ac reg=15 this Lcom/google/android/contacts/EditContactActivity;
0x0002 - 0x00ac reg=9 values Landroid/content/ContentValues;
0x000b - 0x00ac reg=11 contactEntryCount I
0x000c - 0x00ac reg=5 i I
0x0018 - 0x0045 reg=8 entry Lcom/google/android/contacts/EditContactActivity$EditEntry;
0x0024 - 0x0045 reg=7 data Ljava/lang/String;
0x004e - 0x00ac reg=10 contactUri Landroid/net/ContentURI;
0x0054 - 0x00ac reg=6 entryCount I
0x0061 - 0x009e reg=8 entry Lcom/google/android/contacts/EditContactActivity$EditEntry;
0x0082 - 0x009e reg=7 data Ljava/lang/String;
set path=c:jdk1.5.0bin;%path%
export PATH=/path/to/your/java:$PATH
java version "1.5.0_12"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_12-b04)
Java HotSpot(TM) Client VM (build 1.5.0_12-b04, mixed mode)
open a command window, type:cd e:pathtoyourrun.bat
run.bat
open a terminal, type:cd /path/to/your/run.sh
sh run.sh
chmod 744 /path/to/your/blogsync/build/blogsync.jar
<Files xmlrpc.php>
SecFilterInheritance Off
</Files>
Labels: blog
At home, my boxes are connected to internet by Beijing ADSL.
when connected, Beijing ADSL gives me a dynamic ip and it changes about every 24 hours.
Before I get the dynamic ip by a service provided by oray.net.
However recently the service is broken.
So I have to write a python script to check the dynamic ip from my tp-link router every 3 minutes and if it changed, emails the new dynamic ip to my gmail.
I also write a bash script to run the above python script at boot on my gentoo linux.
The python script:
#!/usr/bin/python
import urllib
import urllib2
import libgmail
import cookielib
import sys
import re
import base64
import socket
import time
from urlparse import urlparse
nowip=''
logfile=open('/var/log/ipsender.log','w')
def log(s):
now=time.strftime('%Y-%m-%d %X')
logfile.write('%s %sn'%(now,s))
logfile.flush()
def gmailsender(to_addr,subject,msg):
username='xxx@gmail.com'
password='xxx'
ga=libgmail.GmailAccount(username,password)
ga.login()
gmsg=libgmail.GmailComposedMessage(to_addr,subject,msg)
ga.sendMessage(gmsg)
def check():
global nowip
timeout=10
socket.setdefaulttimeout(timeout)
username = 'admin'
password = 'xxx'
try:
theurl='http://192.168.1.1/userRpm/StatusRpm.htm'
req = urllib2.Request(theurl)
base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
authheader = "Basic %s" % base64string
req.add_header("Authorization", authheader)
handle = urllib2.urlopen(req)
str=handle.read()
ss='var wanPara = new Array'
start=str.index(ss)+ss.__len__()
end=str.index(';',start)
s2=str[start:end]
log(s2)
t=eval(s2)
log(t[2])
handle.close()
if nowip!=t[2]:
nowip=t[2]
gmailsender('mygmail@gmail.com','ddnsip===%s'%nowip,s2)
log('send %s successfully.'%nowip)
else:
log('ddnsip remains %s.'%nowip)
except:
log('Unexpected error:', sys.exc_info()[0])
def main():
while True:
check()
time.sleep(3*60)
main()
#!/sbin/runscript
# Copyright 1999-2004 Gentoo Foundation
start() {
ebegin "Starting ipsender"
nohup python /home/zeaster/amp/ipsender.py >> /var/log/ipsender-nohup.log&
eend $?
}
stop() {
ebegin "Stopping ipsender unsuccessfully"
eend $?
}
Labels: opensource
How to wake up your computer on the LAN?
the answer is just to send a Magic Packet to your computer on port 7 or 9.
However when your computer is down, it has no ip, so send it to the broadcast ip
the following python script implements the above idea.
import struct, socket
def wake_on_lan(ether_addr, inet_addr):
addr_byte=ether_addr.split(':')
hw_addr=struct.pack('BBBBBB',
int(addr_byte[0],16),
int(addr_byte[1],16),
int(addr_byte[2],16),
int(addr_byte[3],16),
int(addr_byte[4],16),
int(addr_byte[5],16))
msg='\xff'*6+hw_addr*16
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(msg, (inet_addr,7))
s.close()
wake_on_lan('00:E0:4C:E1:D9:CC', '192.168.1.255')
import socket
from dpkt import ethernet,udp,ip
import dpkt
import struct
import string
iface = "eth1"
mac = "00:0E:35:AB:9B:40"
inet = "192.168.1.6"
debug = 0
def eth_aton(buffer):
addr =''
temp = string.split(buffer,':')
buffer = string.join(temp,'')
for i in range(0, len(buffer), 2):
addr = ''.join([addr,struct.pack('B', int(buffer[i: i + 2], 16))],)
return addr
def buildUdp():
ether_addr='00:E0:4C:E1:D9:CD'
addr_byte=ether_addr.split(':')
hw_addr=struct.pack('BBBBBB',
int(addr_byte[0],16),
int(addr_byte[1],16),
int(addr_byte[2],16),
int(addr_byte[3],16),
int(addr_byte[4],16),
int(addr_byte[5],16))
msg='xff'*6+hw_addr*16
udp_p = udp.UDP()
udp_p.sport = 0x8130
udp_p.dport = 7
udp_p.data = msg
udp_p.ulen += len(udp_p.data)
ip_p = ip.IP()
ip_p.src = socket.inet_aton('192.168.1.6');
ip_p.dst = socket.inet_aton('192.168.1.255');
ip_p.off = 0x4000
ip_p.data = udp_p
ip_p.p = ip.IP_PROTO_UDP
ip_p.len += len(udp_p)
packet = ethernet.Ethernet()
packet.src = eth_aton(mac)
packet.dst = eth_aton('ff:ff:ff:ff:ff:ff')
packet.data = ip_p
packet.type = ethernet.ETH_TYPE_IP
if debug: print dpkt.hexdump(str(packet))
return packet
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
s.bind((iface,ethernet.ETH_TYPE_IP))
packet = buildUdp()
s.send(str(packet))
Labels: opensource
Firstly, the foregoing blogsync 2.0 should be blogsync 0.2. :-)
blogsync is a tool that import your wordpress to blogger from rss xml file or online
Now it's blogsync 0.3 release. and it can import comments from exported wordpress rss xml file to blogger site.
it can be downloaded from:
http://code.google.com/p/blogsync-java/downloads/list
however it can not preserve the published time of the original comments.
so the published time of your imported comment is just the time when you import.
more details can be found at
http://groups.google.com/group/bloggerDev/browse_thread/thread/15c9a45416305f99
It's open source now and comes with new feature.
1 project hosted:
at http://code.google.com/p/blogsync-java
blogsync 0.2 can be downloaded at
http://blogsync-java.googlecode.com/files/blogsync-0.2.zip
2 new feature:
In previous blogsync, it imports wordpress posts to blogger from your wordpress website online.
Now in blogsync 0.2, it can import wordpress posts to blogger from a rss xml file that exported by wordpress.
when blogsync 0.1, the common errors are such as:
a)[Fatal Error] :1444:21: Invalid byte 1 of 1-byte UTF-8 sequence.
org.apache.xmlrpc.client.XmlRpcClientException: Failed to parse
servers response: Invalid byte 1 of 1-byte UTF-8 sequence.
b)Fatal Error] :1:1: Content is not allowed in prolog.
this is because
a) the server response is not in utf-8 encoding. or
b) the server response is not a valid xml.
when your posts are too big, for example, http://i978.iyublog.com, when export all of this blog's posts, the exported rss xml file is 2064KB.
so when transferring these data through http online, the above errors are easy to reproduce.
Few days ago, I tried to export all posts to a rss xml file, then imports these posts locally from the exported xml file, the above error is hard to reproduce again.
the worst case is that your export file is still invalid xml file or wrong encoding, however it's easy to find these errors and you can try to export it again or edit it manually until you get a valid utf-8 xml file. Now you can import these posts to blogger from the valid utf-8 rss xml file by blogsync 2.0.
ps:
how to export your wordpress posts to a rss xml file?
in wordpress admin page, go to "Manage" page -> "Export" page, there is a link to export all of your posts.
ps2:
within 24 hours, Google allows us to submit at most 50 posts by googe data api.
so after 50 posts, the tool can not import any. only to wait for another 24 hours.