mirror of
https://github.com/GAM-team/GAM.git
synced 2026-07-05 05:11:35 +00:00
phase 2 code complete
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
Build and test GAM / build (false, test, 19, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 20, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
This commit is contained in:
@@ -22,67 +22,63 @@ from gamlib import glcfg as GC
|
||||
from gamlib import glgapi as GAPI
|
||||
|
||||
|
||||
def _getMain():
|
||||
return sys.modules['gam']
|
||||
_gam = lambda: sys.modules['gam']
|
||||
|
||||
|
||||
# Add attachements to an email message
|
||||
def _addAttachmentsToMessage(message, attachments):
|
||||
gam = _getMain()
|
||||
for attachment in attachments:
|
||||
try:
|
||||
attachFilename = gam.setFilePath(attachment[0], GC.INPUT_DIR)
|
||||
attachFilename = _gam().setFilePath(attachment[0], GC.INPUT_DIR)
|
||||
attachContentType, attachEncoding = mimetypes.guess_type(attachFilename)
|
||||
if attachContentType is None or attachEncoding is not None:
|
||||
attachContentType = 'application/octet-stream'
|
||||
main_type, sub_type = attachContentType.split('/', 1)
|
||||
if main_type == 'text':
|
||||
msg = MIMEText(gam.readFile(attachFilename, 'r', attachment[1]), _subtype=sub_type, _charset=gam.UTF8)
|
||||
msg = MIMEText(_gam().readFile(attachFilename, 'r', attachment[1]), _subtype=sub_type, _charset=_gam().UTF8)
|
||||
elif main_type == 'image':
|
||||
msg = MIMEImage(gam.readFile(attachFilename, 'rb'), _subtype=sub_type)
|
||||
msg = MIMEImage(_gam().readFile(attachFilename, 'rb'), _subtype=sub_type)
|
||||
elif main_type == 'audio':
|
||||
msg = MIMEAudio(gam.readFile(attachFilename, 'rb'), _subtype=sub_type)
|
||||
msg = MIMEAudio(_gam().readFile(attachFilename, 'rb'), _subtype=sub_type)
|
||||
elif main_type == 'application':
|
||||
msg = MIMEApplication(gam.readFile(attachFilename, 'rb'), _subtype=sub_type)
|
||||
msg = MIMEApplication(_gam().readFile(attachFilename, 'rb'), _subtype=sub_type)
|
||||
else:
|
||||
msg = MIMEBase(main_type, sub_type)
|
||||
msg.set_payload(gam.readFile(attachFilename, 'rb'))
|
||||
msg.set_payload(_gam().readFile(attachFilename, 'rb'))
|
||||
msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachFilename))
|
||||
message.attach(msg)
|
||||
except (IOError, UnicodeDecodeError) as e:
|
||||
gam.usageErrorExit(f'{attachFilename}: {str(e)}')
|
||||
_gam().usageErrorExit(f'{attachFilename}: {str(e)}')
|
||||
|
||||
# Add embedded images to an email message
|
||||
def _addEmbeddedImagesToMessage(message, embeddedImages):
|
||||
gam = _getMain()
|
||||
for embeddedImage in embeddedImages:
|
||||
try:
|
||||
imageFilename = gam.setFilePath(embeddedImage[0], GC.INPUT_DIR)
|
||||
imageFilename = _gam().setFilePath(embeddedImage[0], GC.INPUT_DIR)
|
||||
imageContentType, imageEncoding = mimetypes.guess_type(imageFilename)
|
||||
if imageContentType is None or imageEncoding is not None:
|
||||
imageContentType = 'application/octet-stream'
|
||||
main_type, sub_type = imageContentType.split('/', 1)
|
||||
if main_type == 'image':
|
||||
msg = MIMEImage(gam.readFile(imageFilename, 'rb'), _subtype=sub_type)
|
||||
msg = MIMEImage(_gam().readFile(imageFilename, 'rb'), _subtype=sub_type)
|
||||
else:
|
||||
msg = MIMEBase(main_type, sub_type)
|
||||
msg.set_payload(gam.readFile(imageFilename, 'rb'))
|
||||
msg.set_payload(_gam().readFile(imageFilename, 'rb'))
|
||||
msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(imageFilename))
|
||||
msg.add_header('Content-ID', f'<{embeddedImage[1]}>')
|
||||
message.attach(msg)
|
||||
except (IOError, UnicodeDecodeError) as e:
|
||||
gam.usageErrorExit(f'{imageFilename}: {str(e)}')
|
||||
_gam().usageErrorExit(f'{imageFilename}: {str(e)}')
|
||||
|
||||
# Send an email
|
||||
def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msgFrom=None, msgReplyTo=None,
|
||||
html=False, charset=None, attachments=None, embeddedImages=None,
|
||||
msgHeaders=None, ccRecipients=None, bccRecipients=None, mailBox=None, threadId=None,
|
||||
action=None):
|
||||
gam = _getMain()
|
||||
Act = gam.Act
|
||||
Ent = gam.Ent
|
||||
Act = _gam().Act
|
||||
Ent = _gam().Ent
|
||||
if charset is None:
|
||||
charset = gam.UTF8
|
||||
charset = _gam().UTF8
|
||||
if action is None:
|
||||
action = Act.SENDEMAIL
|
||||
|
||||
@@ -96,26 +92,26 @@ def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msg
|
||||
toSent.remove(addr)
|
||||
toFailed[addr] = f'{err[0]}: {err[1]}'
|
||||
if toSent:
|
||||
gam.entityActionPerformed([entityType, ','.join(toSent), Ent.MESSAGE, msgSubject], i, count)
|
||||
_gam().entityActionPerformed([entityType, ','.join(toSent), Ent.MESSAGE, msgSubject], i, count)
|
||||
for addr, errMsg in toFailed.items():
|
||||
gam.entityActionFailedWarning([entityType, addr, Ent.MESSAGE, msgSubject], errMsg, i, count)
|
||||
_gam().entityActionFailedWarning([entityType, addr, Ent.MESSAGE, msgSubject], errMsg, i, count)
|
||||
|
||||
def cleanAddr(emailAddr):
|
||||
match = gam.NAME_EMAIL_ADDRESS_PATTERN.match(emailAddr)
|
||||
match = _gam().NAME_EMAIL_ADDRESS_PATTERN.match(emailAddr)
|
||||
if match:
|
||||
emailName = match.group(1)
|
||||
emailAddr = gam.normalizeEmailAddressOrUID(match.group(2), noUid=True, noLower=True)
|
||||
emailAddr = _gam().normalizeEmailAddressOrUID(match.group(2), noUid=True, noLower=True)
|
||||
return (f'{emailName} <{emailAddr}>', emailAddr)
|
||||
emailAddr = gam.normalizeEmailAddressOrUID(emailAddr, noUid=True, noLower=True)
|
||||
emailAddr = _gam().normalizeEmailAddressOrUID(emailAddr, noUid=True, noLower=True)
|
||||
return (emailAddr, emailAddr)
|
||||
|
||||
if msgFrom is None:
|
||||
msgFrom = gam._getAdminEmail()
|
||||
msgFrom = _gam()._getAdminEmail()
|
||||
# Force ASCII for RFC compliance
|
||||
# xmlcharref seems to work to display at least
|
||||
# some unicode in HTML body and is ignored in
|
||||
# plain text body.
|
||||
# msgBody = msgBody.encode('ascii', 'xmlcharrefreplace').decode(gam.UTF8)
|
||||
# msgBody = msgBody.encode('ascii', 'xmlcharrefreplace').decode(_gam().UTF8)
|
||||
if not attachments and not embeddedImages:
|
||||
message = MIMEText(msgBody, ['plain', 'html'][html], charset)
|
||||
else:
|
||||
@@ -145,26 +141,26 @@ def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msg
|
||||
Act.Set(action)
|
||||
if not GC.Values[GC.SMTP_HOST]:
|
||||
if not clientAccess:
|
||||
userId, gmail = gam.buildGAPIServiceObject(API.GMAIL, mailBoxAddr)
|
||||
userId, gmail = _gam().buildGAPIServiceObject(API.GMAIL, mailBoxAddr)
|
||||
if not gmail:
|
||||
Act.Set(parentAction)
|
||||
return
|
||||
else:
|
||||
userId = mailBoxAddr
|
||||
gmail = gam.buildGAPIObject(API.GMAIL)
|
||||
gmail = _gam().buildGAPIObject(API.GMAIL)
|
||||
message['To'] = msgTo if msgTo else userId
|
||||
body = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}
|
||||
if threadId is not None:
|
||||
body['threadId'] = threadId
|
||||
try:
|
||||
result = gam.callGAPI(gmail.users().messages(), 'send',
|
||||
result = _gam().callGAPI(gmail.users().messages(), 'send',
|
||||
throwReasons=[GAPI.SERVICE_NOT_AVAILABLE, GAPI.AUTH_ERROR, GAPI.DOMAIN_POLICY,
|
||||
GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
|
||||
userId=userId, body=body, fields='id')
|
||||
gam.entityActionPerformedMessage([Ent.RECIPIENT, msgTo, Ent.MESSAGE, msgSubject], f"{result['id']}", i, count)
|
||||
_gam().entityActionPerformedMessage([Ent.RECIPIENT, msgTo, Ent.MESSAGE, msgSubject], f"{result['id']}", i, count)
|
||||
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy,
|
||||
GAPI.invalid, GAPI.invalidArgument, GAPI.forbidden, GAPI.permissionDenied) as e:
|
||||
gam.entityActionFailedWarning([Ent.RECIPIENT, msgTo, Ent.MESSAGE, msgSubject], str(e), i, count)
|
||||
_gam().entityActionFailedWarning([Ent.RECIPIENT, msgTo, Ent.MESSAGE, msgSubject], str(e), i, count)
|
||||
else:
|
||||
message['To'] = msgTo if msgTo else mailBoxAddr
|
||||
server = None
|
||||
@@ -175,7 +171,7 @@ def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msg
|
||||
server.starttls(context=ssl.create_default_context(cafile=GC.Values[GC.CACERTS_PEM]))
|
||||
if GC.Values[GC.SMTP_USERNAME] and GC.Values[GC.SMTP_PASSWORD]:
|
||||
if isinstance(GC.Values[GC.SMTP_PASSWORD], bytes):
|
||||
server.login(GC.Values[GC.SMTP_USERNAME], base64.b64decode(GC.Values[GC.SMTP_PASSWORD]).decode(gam.UTF8))
|
||||
server.login(GC.Values[GC.SMTP_USERNAME], base64.b64decode(GC.Values[GC.SMTP_PASSWORD]).decode(_gam().UTF8))
|
||||
else:
|
||||
server.login(GC.Values[GC.SMTP_USERNAME], GC.Values[GC.SMTP_PASSWORD])
|
||||
result = server.send_message(message)
|
||||
@@ -183,7 +179,7 @@ def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msg
|
||||
checkResult(Ent.RECIPIENT_CC, ccRecipients)
|
||||
checkResult(Ent.RECIPIENT_BCC, bccRecipients)
|
||||
except smtplib.SMTPException as e:
|
||||
gam.entityActionFailedWarning([Ent.RECIPIENT, msgTo, Ent.MESSAGE, msgSubject], str(e), i, count)
|
||||
_gam().entityActionFailedWarning([Ent.RECIPIENT, msgTo, Ent.MESSAGE, msgSubject], str(e), i, count)
|
||||
if server:
|
||||
try:
|
||||
server.quit()
|
||||
|
||||
Reference in New Issue
Block a user