My python code selects some mails and move them to another folder.
# A.py
def __init__(self):
account = conf.account
password = conf.password
server = conf.imap_server
port = conf.imap_port
self.mail = imaplib.IMAP4_SSL(host=server, port=port)
try:
self.mail.login(account, password)
except imaplib.IMAP4.error as e:
self.logger.error("Cannot login to STMP server: %s" % str(e))
def move_handled_mails(self, mail_list, suffix=0):
archiving_folder = ''.join([str(current_year), '-', str(current_month), '-', str(suffix)])
self.mail.debug = 4
typ, data = self.mail.select(archiving_folder)
if typ != 'OK':
if "NONEXISTENT" in data[0].decode():
self.mail.create(archiving_folder)
typ, data = self.mail.select(archiving_folder)
if "Too many mail in folder" in data[0].decode():
return self.move_handled_mails(mail_list, suffix+1)
if typ != 'OK':
exit()
for num in mail_list:
print(num)
typ, data = self.mail.uid('COPY', num, archiving_folder)
if typ == 'OK':
typ, data = self.mail.uid('STORE', num, '+FLAGS', '(\\Deleted)')
if typ != 'OK':
exit()
print("Executing expunge")
typ, data = self.mail.expunge()
if typ != 'OK':
exit()
def run(self):
res, nums = self.mail.select() # default=INBOX
if res != 'OK':
self.logger.error(nums)
exit()
typ, msgnums = self.mail.uid('search', None, 'ALL')
mail_list = msgnums[0].split()
self.move_handled_mails(mail_list)
At the move_handled_mails method, creating a folder works well, but moving mails doesn't work.
Moreover, when I print all the typs and datas, they are printed as OK and None repectively.
After running the code, no error occurs, but no mail is moved either.
What could be a problem, and how should I debug this problem?
Debug log after adding self.mail.debug=4:
Mail list: [b'7144291']
03:12.87 > b'GBDI2 SELECT 2021-11-0'
03:13.04 < b'* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)'
03:13.04 < b'* OK [PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft \\*)] Flags permitted.'
03:13.04 < b'* 13534 EXISTS'
03:13.04 < b'* 0 RECENT'
03:13.04 < b'* OK [UNSEEN 1] First unseen.'
03:13.04 < b'* OK [UIDVALIDITY 119] UIDs valid'
03:13.04 < b'* OK [UIDNEXT 7129395] Predicted next UID'
03:13.04 < b'* OK [NOMODSEQ] No permanent modsequences'
03:13.04 < b'GBDI2 OK [READ-WRITE] Select completed.'
b'7144291'
03:13.04 > b'GBDI3 UID COPY 7144291 2021-11-0'
03:13.16 < b'GBDI3 OK No messages copied.'
03:13.16 > b'GBDI4 UID STORE 7144291 +FLAGS (\\Deleted)'
03:13.30 < b'GBDI4 OK Store completed.'
Executing expunge
03:13.30 > b'GBDI5 EXPUNGE'
03:13.30 < b'GBDI5 OK Expunge completed.'
Don't select the folder you're moving to. UIDs are only meaningful in their source folder. You're switching to the destination folder, then trying to move a message out of it, and that message doesn't exist.
Remove this line:
typ, data = self.mail.select(archiving_folder)
Or, at least, if you need it to check that the destination folder exists, you must switch back to the source folder: self.mail.select('INBOX') or similar.
Related
SCRIPT ERROR: #sessionmanager/server/host_lock.lua:25: attempt to compare number with nil
[script:sessionmanage]> handler (#sessionmanager/server/host_lock.lua:25)
the script:
-- whitelist c2s events
RegisterServerEvent('hostingSession')
RegisterServerEvent('hostedSession')
-- event handler for pre-session 'acquire'
local currentHosting
local hostReleaseCallbacks = {}
-- TODO: add a timeout for the hosting lock to be held
-- TODO: add checks for 'fraudulent' conflict cases of hosting attempts (typically whenever the host can not be reached)
AddEventHandler('hostingSession', function()
-- if the lock is currently held, tell the client to await further instruction
if currentHosting then
TriggerClientEvent('sessionHostResult', source, 'wait')
-- register a callback for when the lock is freed
table.insert(hostReleaseCallbacks, function()
TriggerClientEvent('sessionHostResult', source, 'free')
end)
return
end
-- if the current host was last contacted less than a second ago
if GetHostId() >= 1 then
if GetPlayerLastMsg(GetHostId()) < 1000 then
TriggerClientEvent('sessionHostResult', source, 'conflict')
return
end
end
hostReleaseCallbacks = {}
currentHosting = source
TriggerClientEvent('sessionHostResult', source, 'go')
-- set a timeout of 5 seconds
SetTimeout(5000, function()
if not currentHosting then
return
end
currentHosting = nil
for _, cb in ipairs(hostReleaseCallbacks) do
cb()
end
end)
end)
AddEventHandler('hostedSession', function()
-- check if the client is the original locker
if currentHosting ~= source then
-- TODO: drop client as they're clearly lying
print(currentHosting, '~=', source)
return
end
-- free the host lock (call callbacks and remove the lock value)
for _, cb in ipairs(hostReleaseCallbacks) do
cb()
end
currentHosting = nil
end)
EnableEnhancedHostSupport(true)
i tried searching on google but i didnt found anything
correct the block:
if GetHostId() >= 1 then
if GetPlayerLastMsg(GetHostId()) < 1000 then
TriggerClientEvent('sessionHostResult', source, 'conflict')
return
end
end
here you need to check for nil or not allow nil when comparing numbers:
local HostId = GetHostId() or 0
if HostId >= 1 then
if GetPlayerLastMsg(HostId) < 1000 then
TriggerClientEvent('sessionHostResult', source, 'conflict')
return
end
end
I've written a couple production BPF agents, but my approach is very iterative until I please the verifier and can move on. I've reached my limit again.
Here's a program that works if I have one fewer && condition -- and breaks otherwise. The confusing part is that the warning implies that 103 insns is greater-than at most 4096 insns. There's obviously something I'm misunderstanding about how this is all strung together.
My ultimate goal is to do logging based on a process' environment -- so alternative approaches are welcome. :)
Error:
$ sudo python foo.py
bpf: Argument list too long. Program too large (103 insns), at most 4096 insns
Failed to load BPF program b'tracepoint__sched__sched_process_exec': Argument list too long
BPF Source:
#include <linux/mm_types.h>
#include <linux/sched.h>
#include <linux/version.h>
int tracepoint__sched__sched_process_exec(
struct tracepoint__sched__sched_process_exec* args
) {
struct task_struct* task = (typeof(task))bpf_get_current_task();
const struct mm_struct* mm = task->mm;
unsigned long env_start = mm->env_start;
unsigned long env_end = mm->env_end;
// Read up to 512 environment variables -- only way I could find to "limit"
// the loop to satisfy the verifier.
char var[12];
for (int n = 0; n < 512; n++) {
int result = bpf_probe_read_str(&var, sizeof var, (void*)env_start);
if (result <= 0) {
break;
}
env_start += result;
if (
var[0] == 'H' &&
var[1] == 'I' &&
var[2] == 'S' &&
var[3] == 'T' &&
var[4] == 'S' &&
var[5] == 'I' &&
var[6] == 'Z' &&
var[7] == 'E'
) {
bpf_trace_printk("Got it: %s\n", var);
break;
}
}
return 0;
}
Basic loader program for reproducing:
#!/usr/bin/env python3
import sys
from bcc import BPF
if __name__ == '__main__':
source = open("./foo.c").read()
try:
BPF(text=source.encode("utf-8")).trace_print()
except Exception as e:
error = str(e)
sys.exit(error)
bpf: Argument list too long. Program too large (103 insns), at most 4096 insns
Looking at the error message, my guess would be that your program has 103 instructions and it's rejected because it's too complex. That is, the verifier gave up before analyzing all instructions on all paths.
On Linux 5.15 with a privileged user, the verifier gives up after reading 1 million instructions (the complexity limit). Since it has to analyze all paths through the program, a program with a small number of instructions can have a very high complexity. That's particularly the case when you have loops and many conditions, as is your case.
Why is the error message confusing? This error message is coming from libbpf.c:
if (ret < 0 && errno == E2BIG) {
fprintf(stderr,
"bpf: %s. Program %s too large (%u insns), at most %d insns\n\n",
strerror(errno), attr->name, insns_cnt, BPF_MAXINSNS);
return -1;
}
Since the bpf(2) syscall returns E2BIG both when the program is too large and when its complexity is too high, libbpf prints the same error message for both cases, always with at most 4096 instructions. I'm confident upstream would accept a patch to improve that error message.
I'm working with NodeMCU (docs here http://nodemcu.readthedocs.io/) trying to send an email through SMTP. I got this script off the net and everything seems to be working okay as there are no errors but I don't see any emails in my box, so something must be going wrong. Using the display function as the send callback prints nil unfortunately.
I was able to send smtp email through simple curl so I know that google will accept smtp requests through command line and these settings are correct. Also according to this thread it is possible, they are doing the same thing sending raw strings to gmail's smtp service (http://www.esp8266.com/viewtopic.php?f=24&t=1231&start=8).
-- The email and password from the account you want to send emails from
MY_EMAIL = "REDACTED"
EMAIL_PASSWORD = "REDACTED"
-- The SMTP server and port of your email provider.
-- If you don't know it google [my email provider] SMTP settings
SMTP_SERVER = "smtp.gmail.com"
SMTP_PORT = "465"
-- The account you want to send email to
mail_to = "REDACTED"
-- Your access point's SSID and password
SSID = "REDACTED"
SSID_PASSWORD = "REDACTED"
-- configure ESP as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)
email_subject = ""
email_body = ""
count = 0
local smtp_socket = nil -- will be used as socket to email server
-- The display() function will be used to print the SMTP server's response
function display(sck,response)
print(response)
end
-- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence.
-- I was going to use socket callbacks but the code would not run callbacks after the first 3.
function do_next()
if(count == 0)then
count = count+1
IP_ADDRESS = wifi.sta.getip()
smtp_socket:send("HELO "..IP_ADDRESS.."\r\n")
elseif(count==1) then
count = count+1
smtp_socket:send("AUTH LOGIN\r\n")
elseif(count == 2) then
count = count + 1
smtp_socket:send("REDACTED".."\r\n")
elseif(count == 3) then
count = count + 1
smtp_socket:send("REDACTED".."\r\n")
elseif(count==4) then
count = count+1
smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")
elseif(count==5) then
count = count+1
smtp_socket:send("RCPT TO:<" .. mail_to ..">\r\n")
elseif(count==6) then
count = count+1
smtp_socket:send("DATA\r\n")
elseif(count==7) then
count = count+1
local message = string.gsub(
"From: \"".. MY_EMAIL .."\"<"..MY_EMAIL..">\r\n" ..
"To: \"".. mail_to .. "\"<".. mail_to..">\r\n"..
"Subject: ".. email_subject .. "\r\n\r\n" ..
email_body,"\r\n.\r\n","")
smtp_socket:send(message.."\r\n.\r\n")
elseif(count==8) then
count = count+1
tmr.stop(0)
smtp_socket:send("QUIT\r\n")
print("msg sent")
else
smtp_socket:close()
end
print(count)
end
-- The connectted() function is executed when the SMTP socket is connected to the SMTP server.
-- This function will create a timer to call the do_next function which will send the SMTP commands
-- in sequence, one by one, every 5000 seconds.
-- You can change the time to be smaller if that works for you, I used 5000ms just because.
function connected(sck)
tmr.alarm(0,5000,1,do_next)
end
-- #name send_email
-- #description Will initiated a socket connection to the SMTP server and trigger the connected() function
-- #param subject The email's subject
-- #param body The email's body
function send_email(subject,body)
count = 0
email_subject = subject
email_body = body
smtp_socket = net.createConnection(net.TCP,0)
smtp_socket:on("connection",connected)
smtp_socket:on("receive",display)
smtp_socket:connect(SMTP_PORT, SMTP_SERVER)
end
-- Send an email
send_email("ESP8266", "[[Hi, How are your IoT projects coming along? Best Wishes,ESP8266]]")
I am available to answer questions regarding this.
A couple of points:
The old example from esp8266.com you mentioned uses consecutive socket:send calls which doesn't work anymore in recent firmwares, see http://nodemcu.readthedocs.io/en/dev/en/modules/net/#netsocketsend. It was a "bug" in the SDK this ever worked.
SMTP port 465 usually implies SSL/TLS connections. You need a firmware that supports that. Otherwise use port 25.
There's an example right in the NodeMCU repo at https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/email/send_email_smtp.lua
I assume you did replace the placeholder at do_next count 2/3 with the base64 encoded username and password? Contrary to the example script which requires a Lua encoder module you may want to use the corresponding NodeMCU module, see http://nodemcu.readthedocs.io/en/dev/en/modules/encoder/#encodertobase64.
I took your script, a recent NodeMCU firmware, changed port to 25, added base64 encode user/pw and was able to successfully deliver an email to myself.
Update 2016-07-05
Full script including WiFi init.
MY_EMAIL = "myself#my-TLD.com"
MY_EMAIL_B64 = "base64-encoded-email"
EMAIL_PASSWORD_B64 = "base64-encoded-password"
SMTP_SERVER = "my-ISPs-server"
SMTP_PORT = 25
mail_to = "myself#my-TLD.com"
email_subject = ""
email_body = ""
count = 0
smtp_socket = nil
function display(sck,response)
print(response)
end
function do_next()
if(count == 0)then
count = count+1
local IP_ADDRESS = wifi.sta.getip()
smtp_socket:send("HELO "..IP_ADDRESS.."\r\n")
elseif(count==1) then
count = count+1
smtp_socket:send("AUTH LOGIN\r\n")
elseif(count == 2) then
count = count + 1
smtp_socket:send(MY_EMAIL_B64.."\r\n")
elseif(count == 3) then
count = count + 1
smtp_socket:send(EMAIL_PASSWORD_B64.."\r\n")
elseif(count==4) then
count = count+1
smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")
elseif(count==5) then
count = count+1
smtp_socket:send("RCPT TO:<" .. mail_to ..">\r\n")
elseif(count==6) then
count = count+1
smtp_socket:send("DATA\r\n")
elseif(count==7) then
count = count+1
local message = string.gsub(
"From: \"".. MY_EMAIL .."\"<"..MY_EMAIL..">\r\n" ..
"To: \"".. mail_to .. "\"<".. mail_to..">\r\n"..
"Subject: ".. email_subject .. "\r\n\r\n" ..
email_body,"\r\n.\r\n","")
smtp_socket:send(message.."\r\n.\r\n")
elseif(count==8) then
count = count+1
tmr.stop(0)
smtp_socket:send("QUIT\r\n")
else
smtp_socket:close()
end
end
function connected(sck)
tmr.alarm(0,3000,1,do_next)
end
function send_email(subject,body)
count = 0
email_subject = subject
email_body = body
smtp_socket = net.createConnection(net.TCP,0)
smtp_socket:on("connection",connected)
smtp_socket:on("receive",display)
smtp_socket:connect(SMTP_PORT,SMTP_SERVER)
end
SSID = "my-SSID"
SSID_PASSWORD = "my-WiFi-password"
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
tmr.alarm(1, 1000, 1, function()
if wifi.sta.getip()== nil then
print("IP unavaiable, Waiting...")
else
tmr.stop(1)
print("Config done, IP is "..wifi.sta.getip())
send_email(
"ESP8266",
[[Hi,
How are your IoT projects coming along?
Best Wishes,
ESP8266]])
end
end)
I'm writing a mod for a game to allow me to use a second screen with a set of stats. Now I send the data and receive, however there's extra characters when I receive the data, such as , ' ). This is causing issue's preventing me to create an int variable. I've tried stripping these characters but still having problems. This is the error spat out: ValueError: invalid literal for int(*) with base 10: "(0'"
Here's what i'm sending:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '192.168.0.2'
port = 9000
s.bind((host,port))
s.listen(5)
conn, addr = s.accept()
print ('Got connection from', addr)
while True:
#--- RPM --
rpm = info.physics.rpms
max_rpm = info.static.maxRpm
if rpm != 0:
rpm_percent = int(rpm/max_rpm*100)
else:
rpm_percent = 0
#--- SPEED ---
speed = int(info.physics.speedKmh/1.609344)
#--- GEAR ---
gear = info.physics.gear - 1
if gear == 0:
gear = str("N")
elif gear < 0:
gear = str("R")
#--- FUEL ---
fuel = info.physics.fuel
max_fuel = info.static.maxFuel
if fuel != 0:
fuel_percent = int(fuel/max_fuel*100)
else:
fuel_percent = 0
#--- BRAKING ---
brake = info.physics.brake
braking_lvl = int(brake/100*10000)
#--- LAP ---
current_time = info.graphics.currentTime
#--- SEND DATA ---
time.sleep(.1)
#print_data = 'Speed: ', speed, 'RPM: ', rpm_percent, 'Gear: ', gear, 'Braking: ', braking_lvl, 'Fuel: ', fuel, fuel_percent,'Lap Time: ', current_time
send_data = (speed, ';', rpm, ';', rpm_percent, ';', gear, ';', braking_lvl, ';', fuel, ';', fuel_percent)
conn.send(str(send_data).encode('ascii'))
print(send_data)
s.close()
And on the client, which has the errors:
data = s.recv(1024).decode('ascii').replace(' ', '').replace("'", '').replace(')', '').replace(',', '')
data = data.split(';')
speed = int(data[0])
rpm = int(data[1])
rpm_percentage = int(data[2])
gear = str(data[3])
breaking_lvl = int(data[4])
fuel = int(data[5])
fuel_percentage= int(data[6])
Why is it seeing these extra characters? And what's the most effective method to remove them / prevent them?
Cheers.
send_data is a tuple. If you call str(); it returns its string representation '(item, item)'. To read it back you would need eval() or ast.literal_eval() (in simple cases). You could use json format instead.
On the server:
sock.sendall(json.dumps(data).encode('utf-8'))
On the client (assuming the connection is closed after receiving the response from the server):
response = []
while True:
chunk = sock.recv(1024)
if not chunk: # EOF
break
response.append(chunk)
data = json.loads(b"".join(response).decode('utf-8'))
You need to check how much data you receive, and ensure that the string is null terminated at the end of the data that was received, otherwise you will be parsing random data.
For reliability, you should send a fixed length message that tells the client how much data to expect. Then the client can ensure that it receives all the data sent, and no more.
We are are setting a the IMAP flags using the Java Mail API. Is there is a way to look at these flags in Thunderbird or other client for debugging purposes?
You can learn enough of IMAP to use socat to try yourself. Here's a sample exchange, I've marked my input with >, and responses with <:
$ socat READLINE ssl:imap.gmail.com:993,verify=0,crlf
< * OK Gimap ready for requests from [ip]
> a LOGIN user#gmail.com password
< * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE ENABLE MOVE CONDSTORE ESEARCH
< a OK user#gmail.com User authenticated (Success)
> a SELECT INBOX
< * FLAGS (\Answered \Flagged \Draft \Deleted \Seen $Forwarded)
< * OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen $Forwarded \*)] Flags permitted.
< * OK [UIDVALIDITY 7] UIDs valid.
< * 836 EXISTS
< * 0 RECENT
< * OK [UIDNEXT 36515] Predicted next UID.
< * OK [HIGHESTMODSEQ 3346208]
< a OK [READ-WRITE] INBOX selected. (Success)
> a FETCH 810:820 (FLAGS)
< * 810 FETCH (FLAGS (\Flagged))
< * 811 FETCH (FLAGS ())
< * 812 FETCH (FLAGS (\Seen))
< * 813 FETCH (FLAGS (\Seen))
< * 814 FETCH (FLAGS (\Seen))
< * 815 FETCH (FLAGS (\Seen))
< * 816 FETCH (FLAGS (\Seen))
< * 817 FETCH (FLAGS ())
< * 818 FETCH (FLAGS ())
< * 819 FETCH (FLAGS ())
< * 820 FETCH (FLAGS ())
< a OK Success
> a LOGOUT
< * BYE LOGOUT Requested
< a OK 73 good day (Success)
You will want to at least skim RFC 3501, so that you understand UIDs and message sequence numbers, and section 6.4.5 will tell you the various things you can ask for in a FETCH command, such as flags, envelope, etc.
Each command is preceded by an arbitrary tag. I've used just a in the examples. It's intended to allow pipelining of commands and responses, so that they can be matched up.
The LOGIN command is just the username and password, and SELECT INBOX chooses the mailbox for the following commands to use. FETCH takes a sequence list (in the example, I said messages with sequence numbers between 810 and 820, and a list of items to fetch, in this case, just the flags.
Get Trojitá, it shows e-mail flags by default. I have no idea how to configure other MUAs to do the same, but I suspect many of them can do this for you as well.