473,770 Members | 5,862 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Problem with uudecode

I made a Python script which takes Usenet message bodies from a database,
decodes uuencoded contents and inserts them as Large Object into a
PostGreSQL database. However, it appears that the to last few bytes
of uudecoded data are always mangled. Take a look of this hexdump output:

Originals (decoded with Pan, each line is from a different file):
000c2c0 e1bf 00ff 2541 a9e4 a724 d9ff
0011a10 ff54 00d9
00093e0 fb4f a80d ffd9 c200 ffef 00d9

Decoded by the script:
000c2c0 e1bf 00ff 2541 a9e4 a724 d0ff
0011a10 ff54 00d8
00093e0 fb4f a80d ffd9 c200 ffef 00d8

As you can see, one of the last two bytes gets altered in all cases.

The script also outputs the decoded file to disk for debugging purposes,
and the database large object and filesystem file match so it can't be a
PostGreSQL problem.

So, if anyone has any idea what is wrong, please tell me ? I can't found
any reason why the bytes would get mangled...

The script follows:

#!/usr/local/bin/python2.3

# Insert message contents into the database, for each message-id already there
#
# Copyright 2004 by Juho Saarikko
# License: GNU General Public License (GPL) version 2
# See www.gnu.org for details

from pyPgSQL import libpq
import nntplib
import sys
import string
import regex
import sha
import imghdr
import binascii
import StringIO
import os

def strip_trailing_ dots(n):
tmp = []
for i in range(len(n)):
if n[i][-1] == "," or n[i][-1] == ".":
tmp.append(n[i][:-1])
else:
tmp.append(n[i])
return tmp

def findmimetype(bo dy, filename):
tail4 = string.lower(fi lename[-5:])
tail3 = string.lower(fi lename[-4:])
if tail4 == ".jpeg":
return "image/jpeg"
if tail3 == ".jpg":
return "image/jpeg"
if tail3 == ".png":
return "image/png"
if tail3 == ".jpe":
return "image/jpeg"
if tail3 == ".gif":
return "image/gif"
return None

def insert_picture( conn, image, filename):
hash = sha.new(image)
qhash = libpq.PgQuoteBy tea(hash.digest ())
candidates = conn.query("SEL ECT id, picture FROM pictures WHERE hash = " + qhash )
if candidates.ntup les > 0:
print "Found possible mathces " + str(candidates. ntuples)
for x in range(candidate s.ntuples):
old = candidates.getv alue(x, 1)
old.open("r")
oldpic = old.read()
old.close()
if oldpic == image:
print "Found a match"
ret = (candidates.get value(x,0), 1)
return ret
mime = findmimetype(im age, filename)
print "attempting to get mimetype"
if mime == None:
print "No mimetype found"
ret = (0, 0)
return ret
mime = libpq.PgQuoteSt ring(mime)
mimeres = conn.query("SEL ECT id FROM mimetypes WHERE mimetype = " + mime)
if mimeres.ntuples == 0:
conn.query("INS ERT INTO mimetypes (mimetype) VALUES (" + mime + ")")
mimeres = conn.query("SEL ECT id FROM mimetypes WHERE mimetype = " + mime)
mimetype = mimeres.getvalu e(0,0)
picture = conn.lo_creat(" rw")
picture.open("r w")
picture.write(i mage)
picture.close()
tmp = conn.query("INS ERT INTO pictures (hash, mimetype, picture) VALUES (" + qhash + ", " +str(mimetype) + ", " + picture.name + ")")
temp = conn.query("SEL ECT id FROM pictures WHERE OID = " + str(tmp.oidValu e))
id = temp.getvalue(0 ,0)
ret = (id, 0)
return ret

def try_decode_and_ insert_uuencode d(conn, id):
begin = regex.compile(" begin [0-9]+ \(.*\)")
conn.query("BEG IN")
basedir = "kuvat"
message = conn.query("SEL ECT data FROM fragments_bodie s WHERE message = " + str(id) + " ORDER BY line")
# print message.ntuples

keywords = []
picids = []
newpicids = []
n = 0
s = ""
picid = 0
print 'Starting message id ' + str(id)
while n < message.ntuples :
# print "length of row " + str(n)
# print str(message.get length(n, 0))
# print "Got length"
abcddummy = message.getvalu e(n, 0)
# print "Got value"
s = message.getvalu e(n, 0)
# print "Got s"
if begin.match(s) > 0:
# if match_beginning (s) > 0:
# print "Begin matched"
body = []
file = begin.group(1)
# file = get_file_name(s )
# print "Starting to decode, at line " + str(n + 1)
for k in range(n+1, message.ntuples ):
# print "Decodind row " + str(k)
s = message.getvalu e(k, 0)
if s[:3] == "end":
n = k + 1
break
try:
body.append(bin ascii.a2b_uu(s) )
except:
try:
bytes = (((ord(s[0])-32) & 63) * 4 + 3) / 3
body.append(bin ascii.a2b_uu(s[:bytes]))
except:
print "Broken attachment in message " + str(id)
conn.query("ROL LBACK")
return
# print "Got to end, at line " + str(n)
# print "Attempting to join body"
body = string.join(bod y, "")
# print "Attempting to hash body"
# hash = sha.new(body)
# qhash = libpq.PgQuoteBy tea(hash.digest ())
# qbody = libpq.PgQuoteBy tea(body)
# print "Attempting to find whether the pic already exists"
print "Mimetype returned " + str(findmimetyp e(body, file))
# temporary = open("dummy", "wb")
# temporary.write (body)
# temporary.close ()
# dummy.write("ds fds")
print "Calling insert function"
picid, exists = insert_picture( conn, body, file)
print "Returned from insert function with value " + str(picid)
if picid > 0:
# already = conn.query("SEL ECT id FROM pictures WHERE hash = " + qhash)
# if already.ntuples == 0:
# print "Attempting to find mimetype"
# mimetype = findmimetype(bo dy, file)
# print "Found mimetype"
# if mimetype != None:
# o = conn.query("INS ERT INTO pictures (picture, hash, mimetype) VALUES (" + qbody + ", " + qhash + ", " + libpq.PgQuoteSt ring(mimetype) + ")")
# already = conn.query("SEL ECT id FROM pictures WHERE OID = " + str(o.oidValue( )));
# already = conn.query("SEL ECT id FROM pictures WHERE data = " + qbody)
# already = conn.query("SEL ECT id FROM pictures WHERE hash = " + qhash)
# print "Attempting to insert hash and mimetype"
# conn.query("INS ERT INTO pictures (hash, mimetype) VALUES (" + qhash + ", " + libpq.PgQuoteSt ring(mimetype) + ")")
# print "Attempting to get id"
# already = conn.query("SEL ECT id FROM pictures WHERE hash = " + qhash)
# print "Attempting to get value"
# picid = already.getvalu e(0, 0)
print picid
print "Attempting to OK dir"
if os.access(based ir + "/tmp", os.F_OK) != 1:
os.mkdir(basedi r + "/tmp")
fh = open(basedir + "/tmp/" + str(picid), "wb")
fh.write(body)
fh.close()
print "File ok"
picids.append(p icid)
if exists == 0:
newpicids.appen d(picid)
if file != "":
keywords.append (file)
# else:
# picid = already.getvalu e(0, 0)
# if already.ntuples == 0:
# conn.query("ROL LBACK")
# return
# picids.append(p icid)
# if already.ntuples == 0:
# print "already.ntuple s == 0, ROLLBACKing"
# conn.query("ROL LBACK")
# return
# print "Appending picid"
# picids.append(p icid)
# print "Picid appended"
else:
tmptmp = string.split(s)
tmpkey = strip_trailing_ dots(tmptmp)
if len(tmpkey) > 0:
for j in range(len(tmpke y)):
keywords.append (tmpkey[j])
# print "Adding 1 to n"
n = n + 1
if len(picids) > 0:
print "Found " + str(len(picids) ) + " pictures (" + str(len(newpici ds)) + " new ones)"
# print "Finding Subject"
head = conn.query("SEL ECT contents FROM fragments_heade r_contents WHERE message = " + str(id) + " AND header = (SELECT id FROM fragments_heade r_names WHERE header ilike 'Subject')")
if head.ntuples > 0:
# print "Splitting Subject"
blah = head.getvalue(0 ,0)
# print str(blah)
blahblah = string.split(st r(blah))
# print "Stripping"
abctmpkey = strip_trailing_ dots(blahblah)
# print "Stripping done"
# print "Really"
tmpkey = abctmpkey
# print "Subject split"
if len(tmpkey) > 0:
for j in range(len(tmpke y)):
keywords.append (tmpkey[j])
o = conn.query("INS ERT INTO messages DEFAULT VALUES")
mid = conn.query("SEL ECT id FROM messages WHERE OID = " + str(o.oidValue) )
messageid = mid.getvalue(0, 0)
nresult = conn.query("SEL ECT contents FROM fragments_heade r_contents WHERE message = " + str(id) + " AND header = (SELECT id FROM fragments_heade r_names WHERE header ILIKE 'Newsgroups')")
if nresult.ntuples > 0:
for x in range(nresult.n tuples):
newsgroups = string.split(nr esult.getvalue( x, 0), ",")
if len(newsgroups) > 0:
for y in range (len(newsgroups )):
newsgroup = libpq.PgQuoteSt ring(newsgroups[y])
ngroupres = conn.query("SEL ECT id FROM newsgroups WHERE name = " + newsgroup)
if ngroupres.ntupl es > 0:
newsgid = ngroupres.getva lue(0, 0)
else:
conn.query("INS ERT INTO newsgroups (name) VALUES (" + newsgroup + ")")
ngrtmpres = conn.query("SEL ECT id FROM newsgroups WHERE name = " + newsgroup)
newsgid = ngrtmpres.getva lue(0, 0)
conn.query("INS ERT INTO messages_ngroup s_glue (message, newsgroup) VALUES (" + str(messageid) + ", " + str(newsgid) + ")")
else:
print "An empty Newsgroups: header at messag " + str(id)
conn.query("ROL LBACK")
return
else:
print "No Newsgroups: header at message " + str(id)
conn.query("ROL LBACK")
return
for x in range(len(picid s)):
conn.query("INS ERT INTO messages_pictur es_glue (message, picture) VALUES (" + str(messageid) + ", " + str(picids[x]) + ")")
if len(keywords) > 0:
for x in range(len(tmpke y)):
qword = libpq.PgQuoteSt ring(str(keywor ds[x]))
tmp = conn.query("SEL ECT id FROM keywords_words WHERE keyword = " + qword)
if tmp.ntuples == 0:
conn.query("INS ERT INTO keywords_words (keyword) VALUES (" + qword + ")")
tmp = conn.query("SEL ECT id FROM keywords_words WHERE keyword = " + qword)
keyid = str(tmp.getvalu e(0, 0))
for y in range(len(picid s)):
conn.query("INS ERT INTO keywords_glue(w ord, picture) VALUES (" + keyid + ", " + str(picids[y]) + ")")
dummyone = "SELECT fragments_heade r_contents.line , fragments_heade r_names.header, "
dummytwo = " fragments_heade r_contents.cont ents FROM fragments_heade r_names, fragments_heade r_contents"
dummythree = " WHERE fragments_heade r_contents.mess age = " + str(id)
dummyfour = " AND fragments_heade r_contents.head er = fragments_heade r_names.id"
head = conn.query(dumm yone + dummytwo + dummythree + dummyfour)
if head.ntuples > 0:
for h in range(head.ntup les):
qhead = libpq.PgQuoteSt ring(str(head.g etvalue(h, 1)))
qcont = libpq.PgQuoteSt ring(str(head.g etvalue(h, 2)))
tmp = conn.query("SEL ECT id FROM header_names WHERE header = " + qhead)
if tmp.ntuples == 0:
conn.query("INS ERT INTO header_names (header) VALUES (" + qhead + ")")
tmp = conn.query("SEL ECT id FROM header_names WHERE header = " + qhead)
headid = str(tmp.getvalu e(0, 0))
line = str(head.getval ue(0, 0))
conn.query("INS ERT INTO header_contents (header, message, line, contents) VALUES (" + headid + ", " + str(messageid) + ", " + line + ", " + qcont + ")")
conn.query("DEL ETE FROM fragments_heade r_contents WHERE message = " + str(id))
conn.query("DEL ETE FROM fragments_bodie s WHERE message = " + str(id))
conn.query("COM MIT")
if len(newpicids) > 0:
tmpdir = basedir + "/tmp/"
for i in range(len(newpi cids)):
picid = newpicids[i]
tmppicname = tmpdir + str(picid)
permpicname = basedir + "/" + str(picid%1000) + "/" + str(picid)
print tmppicname
print permpicname
if os.access(based ir + "/" + str(picid%1000) , os.F_OK) != 1:
os.mkdir(basedi r + "/" + str(picid%1000) )
os.link(tmppicn ame, permpicname)
os.unlink(tmpdi r +str(picid))
else:
print "No pictures found"
conn.query("ROL LBACK")
return
database = libpq.PQconnect db('dbname = kuvat')
items = database.query( "SELECT message FROM whole_attachmen ts")

# try_decode_and_ insert_uuencode d(database, 5407)

for i in range(items.ntu ples):
try:
print 'Starting call ' + str(i)
try_decode_and_ insert_uuencode d(database, items.getvalue( items.ntuples - 1 - i,0))
print ' returned from call ' + str(i)
except:
print 'Some other error occurred at message " + str(i) + ", trying to continue...'
Jul 18 '05 #1
5 2725
>>>>> "Juho" == Juho Saarikko <so***@but.no.s pam> writes:

Juho> I made a Python script which takes Usenet message bodies
Juho> from a database, decodes uuencoded contents and inserts them
Juho> as Large Object into a PostGreSQL database. However, it
Juho> appears that the to last few bytes

I skimmed through your program, and noticed that you use binascii
module uuencode/decode. Have you given the "uu" module a try, to see
if it works better?

Also, get rid of "regex" module, it even gives a DeprecationWarn ing
suggesting switching to "re".

--
Ville Vainio http://tinyurl.com/2prnb
Jul 18 '05 #2
On Tue, 25 May 2004 22:04:24 +0300, Ville Vainio wrote:
>> "Juho" == Juho Saarikko <so***@but.no.s pam> writes:

Juho> I made a Python script which takes Usenet message bodies
Juho> from a database, decodes uuencoded contents and inserts them
Juho> as Large Object into a PostGreSQL database. However, it
Juho> appears that the to last few bytes

I skimmed through your program, and noticed that you use binascii
module uuencode/decode. Have you given the "uu" module a try, to see
if it works better?


I did examine the uu module, but it would seem that I'd had to parse the
message first anyway to get the file name and the non-binary parts of the
message as keywords. Besides, as I understand it, the uu module uses the
binascii module, so if there's something wrong with the binascii module,
the uu module can't possibly work well.

Oh well, I would had to write the parsing engine anyway (or learn to
use the e-mail classes), to properly handle mime and yenc messages. And I
suppose I'd better start using imagemagic to verify the mimetype of
decoded files, instead of just believing the filename. And join together
files that have been spread over multiple messages. Work, work, work...
Also, get rid of "regex" module, it even gives a DeprecationWarn ing
suggesting switching to "re".


I would, if I knew how to make regular expressions; I found the uu-parsing
snippet from the net and built my script around it, but the
regular expression doesn't seem to work with the re module.
Jul 18 '05 #3
Juho Saarikko wrote:
I made a Python script which takes Usenet message bodies from a database,
decodes uuencoded contents and inserts them as Large Object into a
PostGreSQL database. However, it appears that the to last few bytes
of uudecoded data are always mangled. Take a look of this hexdump output:

Originals (decoded with Pan, each line is from a different file):
000c2c0 e1bf 00ff 2541 a9e4 a724 d9ff
0011a10 ff54 00d9
00093e0 fb4f a80d ffd9 c200 ffef 00d9

Decoded by the script:
000c2c0 e1bf 00ff 2541 a9e4 a724 d0ff
0011a10 ff54 00d8
00093e0 fb4f a80d ffd9 c200 ffef 00d8

As you can see, one of the last two bytes gets altered in all cases.

The script also outputs the decoded file to disk for debugging purposes,
and the database large object and filesystem file match so it can't be a
PostGreSQL problem.

So, if anyone has any idea what is wrong, please tell me ? I can't found
any reason why the bytes would get mangled...

The script follows:

[...]
I note that you are dumping words rather than bytes. Is it possible that
the last byte isn't actually a part of the file, that
endianness makes the last byte look like the penultimate byte, and that
what you are seeing is simply noise?

If not then it should probably be looked into ...

regards
Steve
Jul 18 '05 #4
On Tue, 25 May 2004 18:54:44 -0400, Steve Holden wrote:
I note that you are dumping words rather than bytes. Is it possible that
the last byte isn't actually a part of the file, that
endianness makes the last byte look like the penultimate byte, and that
what you are seeing is simply noise?
Well, ImageMagick complains that the image contains errors (altought
Eye of Gnome shows it with no artifacts), so it's likely to be part of the
file itself.

I get both

"display: Premature end of JPEG file"

and

"display: Invalid JPEG file structure: two SOI markers"

errors. The later error prevent ImageMagick's display-command from
displaying the image (but not Eye of Gnome).
If not then it should probably be looked into ...


Looked, looked, but where to start ? The bug could be anywhere from my
script to binascii module to the nntp module to the string.join -function.

Jul 18 '05 #5
Juho Saarikko <so***@but.no.s pam> wrote:
I made a Python script which takes Usenet message bodies from a database,
decodes uuencoded contents and inserts them as Large Object into a
PostGreSQL database. However, it appears that the to last few bytes
of uudecoded data are always mangled. Take a look of this hexdump output:

Originals (decoded with Pan, each line is from a different file):
000c2c0 e1bf 00ff 2541 a9e4 a724 d9ff
0011a10 ff54 00d9
00093e0 fb4f a80d ffd9 c200 ffef 00d9

Decoded by the script:
000c2c0 e1bf 00ff 2541 a9e4 a724 d0ff
0011a10 ff54 00d8
00093e0 fb4f a80d ffd9 c200 ffef 00d8

As you can see, one of the last two bytes gets altered in all cases.
As others have pointed out, it's really the last byte that is getting
altered.
for k in range(n+1, message.ntuples ):
# print "Decodind row " + str(k)
s = message.getvalu e(k, 0)
if s[:3] == "end":
n = k + 1
break
try:
body.append(bin ascii.a2b_uu(s) )
except:
try:
bytes = (((ord(s[0])-32) & 63) * 4 + 3) / 3
body.append(bin ascii.a2b_uu(s[:bytes]))
except:
print "Broken attachment in message " + str(id)
conn.query("ROL LBACK")
return


Your computation of the number of bytes in the uuencoded string will come
up one short: you're not accounting for the length byte. That will have
exactly the effect you describe. You lose the last encoded character,
which means you'll miss the last 6 bits of the file. Change it to this:

bytes = (((ord(s[0])-32) & 63) * 4 + 3) / 3 + 1

However, you should not need to wrap the first binascii.a2b_uu call with
try/except at all. What is happening that causes the error in the first
place? I suspect if you fix the root cause, you could eliminate the except
clause altogether.
--
- Tim Roberts, ti**@probo.com
Providenza & Boekelheide, Inc.
Jul 18 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
3077
by: Bruce Davis | last post by:
I'm having a problem on windows (both 2000 and XP) with a multi-threaded tkinter gui application. The problem appears to be a deadlock condition when a child thread pops up a Pmw dialog window in the context of a main window. The problem does not occur on HPUX or Linux. The following simple example code illustrates the problem and the work around I've come up with; However, I'd like, very much, to get rid of the kludgy work around....
11
3760
by: Kostatus | last post by:
I have a virtual function in a base class, which is then overwritten by a function of the same name in a publically derived class. When I call the function using a pointer to the derived class (ClassB* b; b->func(); ) the base-class function is called instead of the new function in the derived class. All other similar functions (virtual in the base class and overwritten in the the derived class) work fine, it's just this one function. ...
117
7265
by: Peter Olcott | last post by:
www.halting-problem.com
28
5222
by: Jon Davis | last post by:
If I have a class with a virtual method, and a child class that overrides the virtual method, and then I create an instance of the child class AS A base class... BaseClass bc = new ChildClass(); .... and then call the virtual method, why is it that the base class's method is called instead of the overridden method? How do I fix this if I don't know at runtime what the child class is? I'm using Activator.CreateInstance() to load the...
6
3812
by: Ammar | last post by:
Dear All, I'm facing a small problem. I have a portal web site, that contains articles, for each article, the end user can send a comment about the article. The problem is: I the comment length is more that 1249 bytes, then the progress bar of the browser will move too slow and then displaying that the page not found!!!! If the message is less than or equal to 1249 then no problem.
16
4929
by: Dany | last post by:
Our web service was working fine until we installed .net Framework 1.1 service pack 1. Uninstalling SP1 is not an option because our largest customer says service packs marked as "critical" by Microsoft must be installed on their servers. Now german Umlaute (ä, ü, ö) and quotes are returned incorrectly in SOAP fault responses. This can be easily verified: Implement the following in a web service method (just raises a SOAPException with a...
9
7294
by: py | last post by:
Hi, I am encoding a string such as... data = someFile.readlines() encoded = for line in data: encoded.append(binascii.b2a_uu(stringToEncode)) return encoded
2
4556
by: Mike Collins | last post by:
I cannot get the correct drop down list value from a drop down I have on my web form. I get the initial value that was loaded in the list. It was asked by someone else what the autopostback was set to...it is set to false. Can someone show me what I am doing wrong and tell me the correct way? Thank you. In the page load event, I am doing the following:
2
1587
by: Nelluru | last post by:
Hi, I am using PHP 5.2.5 and IIS 5.1 on Windows XP SP3 machine. I am trying to execute an exe by using exec or system command. When I run this php script from the command line it works fine without any problem. When I try to run the script from IE7 the exe is crashing, sample code: <?php exec("C:\\temp\\uudecode.exe c:\\temp\\test.txt");//or system("cmd.exe /c C:\\temp\\uudecode.exe c:\\temp\\test.txt");
0
10053
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10001
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9867
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7415
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6676
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5312
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5449
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3969
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3573
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.