Hello,
we always had issues with caldav and the nextcloud mail client.
To… enable copy and inserting of the calendar into the nextcloud-calendar, we added a little script to make it possible. The functions open a new window to select all shared calendars and make is possible to add the new entry.
Copy into rainloog.js:
`var windowHtml = '<!DOCTYPE html><html><head><title>Add to Calendar</title></head><body><script>var allOptions = "";var optionString = \'<option value="__option__">__option__</option>\';var username = "__username__";var fileLink = "__filelink__";var hostname = "__host__";var eventStart = "";function getStart(textToParse){ let lines = textToParse.split("\\n"); let eventCode = false; for(let i = 0; i < lines.length; i++){ if(lines[i].indexOf("BEGIN:VEVENT")>-1){ eventCode=true; } if(eventCode){ if(lines[i].indexOf("DTSTART")>-1){ return lines[i].replace("DTSTART", "").replace(":", "").replace(";", "") } } }}function getUID(textToParse){ let lines = textToParse.split("\\n"); let eventCode = false; for(let i = 0; i < lines.length; i++){ if(lines[i].indexOf("UID")>-1){ return lines[i].replace("UID", "").replace(":", "").replace(";", "") } }}function timeString(line){ try{ let numbers = ""; for(let i=line.length-1; i>=0; i--){ if(!isNaN(line[i]) && line[i]!="\\n" && line[i] !="\\r"){ numbers += line[i]; } if(numbers.length>=14){ break; } } let sec = numbers[1]+numbers[0]; let min = numbers[3]+numbers[2]; let hour = numbers[5]+numbers[4]; let day = numbers[7]+numbers[6]; let month = numbers[9]+numbers[8]; let year = numbers[13]+numbers[12]+numbers[11]+numbers[10]; return year+"-"+month+"-"+day; } catch(e){ return line; }}function getCalendars(xmlString){ let cals = []; let b = xmlString.split("<cal:calendar/>"); for(let i=0; i<b.length; i++){ if(b[i].lastIndexOf("404")<b[i].lastIndexOf("remote.php")){ let tmp = b[i].substring(b[i].lastIndexOf("remote.php")).split("/<")[0].split("/"); cals.push(tmp[tmp.length-1]); } } return cals;}function getPassword(){ let pw = ""; try{ pw = document.getElementById("pwInput").value; }catch(e){ console.log("No password specified, trying without."); } return pw;}function okFunc(){ let pw = getPassword(); let xmlText = ""; while (xmlText === false || xmlText === ""){ xmlText = getCalXML(username, pw); if (xmlText === false){document.getElementById("pwHint").style.display="block"; document.getElementById("pwDiv").style.display="block"; } } let cals = getCalendars(xmlText); for(let i=0; i<cals.length; i++){ allOptions += optionString.replace("__option__", cals[i]).replace("__option__", cals[i]); } document.getElementById("calendars").innerHTML = allOptions; document.getElementById("choiceDiv").style.display="block";}function getCalXML(username, password){ try{ var xmlHttp = new XMLHttpRequest(); xmlHttp.open( "PROPFIND", "https://"+hostname+"/remote.php/dav/calendars/"+username, false ); xmlHttp.setRequestHeader("Authorization", "Bearer "+btoa(username+":"+password)); xmlHttp.send( null ); return xmlHttp.responseText; } catch(e){ return false; }}function httpGet(theUrl){ var xmlHttp = new XMLHttpRequest(); xmlHttp.open( "GET", theUrl, false ); xmlHttp.send( null ); return xmlHttp.responseText;}function putIcsFile(username, password, dlLink){ let SELECTED_KALENDER = document.getElementById("calendars").value; let content = httpGet(dlLink); eventStart = timeString(getStart(content)); let uid = getUID(content); try{ var xmlHttp = new XMLHttpRequest(); xmlHttp.open( "PUT", "https://"+hostname+"/remote.php/dav/calendars/"+ username + "/" + SELECTED_KALENDER + "/" + uid + ".ics", false ); xmlHttp.setRequestHeader("If-None-Match", "*"); xmlHttp.setRequestHeader("Content-Type", "text/calendar"); xmlHttp.setRequestHeader("Authorization", "Bearer "+btoa(username+":"+password)); xmlHttp.send( content.replace("METHOD:", "X-METHOD:") ); return xmlHttp.responseText; } catch(e){ return false; }}function readyFunc(){ try{ putIcsFile(username, getPassword(), fileLink); } catch(e){ console.log("Network error, while uploading ics file to Calendar. Retry."); return; } if(document.getElementById("jump").checked){ window.open("https://"+hostname+"/index.php/apps/calendar/dayGridMonth/"+eventStart); } window.close();}setTimeout(okFunc, 500);</script><div id="pwDiv" style="display:none"><label style="font-size:30px;">Enter your password for Calendar access:</label><br><input id="pwInput" type="password" style="font-size:30px;width:100%"><button style="font-size:30px;" onclick="okFunc();">Ok</button><label id="pwHint" style="font-size:30px;color:red;display:none;">Invalid password or Connection error!</label></div><br><br><br><div id="choiceDiv" style="display:none"><label style="font-size:30px;">Choose a Calender:</label><select id="calendars" style="font-size:30px;width:100%">__allOptions__</select><br><br><br><input id="jump" type="checkbox">Jump to calendar event</input><br><button onclick="readyFunc();" style="font-size:30px;width:100%">Add to Calendar</button></div></body></html>';
/*Kalenderliste holen.
Wird Oben im HTML benutzt.*/
function getCalXML(username, password)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "PROPFIND", 'https://'+OC.getHostName()+'/remote.php/dav/calendars/'+username, false ); // false for synchronous request
xmlHttp.setRequestHeader("Authorization", "Bearer "+btoa(username+":"+password));
xmlHttp.send( null );
return xmlHttp.responseText;
}
function getUserName(){
return document.head.getAttribute("data-user");
}
/*Funktion, wenn Add-Knopf gedrückt wird.*/
function addFunc(fileName, fileLink) {
let username = getUserName();
createNewWindow(fileLink, username);
}
/*
Parsed die Kalendernamen aus dem XML.
Gibt eine Liste mit den Kalendernamen zurück.
Wird Oben im HTML benutzt.
*/
function getCalendars(xmlString){
let cals = [];
let b = xmlString.split("<cal:calendar/>");
for(let i=0; i<b.length; i++){
if(b[i].lastIndexOf("404")<b[i].lastIndexOf("remote.php")){
let tmp = b[i].substring(b[i].lastIndexOf("remote.php")).split("/<")[0].split("/");
cals.push(tmp[tmp.length-1]);
}
}
return cals;
}
/*
Baut das Fenster
*/
function createNewWindow(dlLink, username){
var Chooser = window.open("about:blank", "Zweitfenster", "width=300,height=400,left=100,top=200");
let newHtml = windowHtml.replace("__username__", username);
newHtml = newHtml.replace("__filelink__", dlLink);
newHtml = newHtml.replace("__host__", OC.getHostName());
Chooser.document.write(newHtml);
Chooser.focus();
}
/*Holt sich die Dateinamen und Links aller Anhänge*/
function getFileInfo(){
var rainloopFrame = document.getElementById("rliframe");
var items = rainloopFrame.contentDocument.getElementsByClassName("attachmentItem");
var names = [];
var links = [];
for(let i=0; i<items.length; i++){
if (items[i].title.endsWith(".ics")){
names.push(items[i].title);
links.push(items[i].getElementsByTagName("a")[0].href);
}
}
return [names, links];
}
function getNamesString(names){
var full="";
for(let i=0; i<names.length; i++){
full += names[i];
}
return full;
}
/*Funktion für GET-Anfragen*/
function httpGet(theUrl)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
/*Parsen der ICS-Datei*/
function getTitle(textToParse){
let lines = textToParse.split("\n")
let eventCode = false;
for(let i = 0; i < lines.length; i++){
if(lines[i].indexOf("BEGIN:VEVENT")>-1){
eventCode=true;
}
if(eventCode){
if(lines[i].indexOf("SUMMARY")>-1){
return lines[i].replace("SUMMARY", "").replace(":", "").replace(";", "")
}
}
}
}
function getStart(textToParse){
let lines = textToParse.split("\n")
let eventCode = false;
for(let i = 0; i < lines.length; i++){
if(lines[i].indexOf("BEGIN:VEVENT")>-1){
eventCode=true;
}
if(eventCode){
if(lines[i].indexOf("DTSTART")>-1){
return lines[i].replace("DTSTART", "").replace(":", "").replace(";", "")
}
}
}
}
function getEnd(textToParse){
let lines = textToParse.split("\n")
let eventCode = false;
for(let i = 0; i < lines.length; i++){
if(lines[i].indexOf("BEGIN:VEVENT")>-1){
eventCode=true;
}
if(eventCode){
if(lines[i].indexOf("DTEND")>-1){
return lines[i].replace("DTEND", "").replace(":", "").replace(";", "")
}
}
}
}
function timeString(line){
try{
let numbers = "";
for(let i=line.length-1; i>=0; i--){
if(!isNaN(line[i]) && line[i]!="\n" && line[i] !="\r"){
numbers += line[i];
}
if(numbers.length>=14){
break;
}
}
let sec = numbers[1]+numbers[0];
let min = numbers[3]+numbers[2];
let hour = numbers[5]+numbers[4];
let day = numbers[7]+numbers[6];
let month = numbers[9]+numbers[8];
let year = numbers[13]+numbers[12]+numbers[11]+numbers[10];
return day+"."+month+"."+year+" at: "+hour+":"+min+" ("+sec+")";
}
catch(e){
return line;
}
}
/*HTML der Vorschautabelle*/
var tableStyle = '<style>\
.calth {\
text-align: left;\
}\
.calth, .caltd {\
padding: 15px;\
}\
.caltable, .calth, .caltd {\
border: 1px solid black;\
border-collapse: collapse;\
}\
</style>'
var tableHtml = '<table class="caltable", style="width: 50%">\
<tr>\
<th class="calth">Title</th><th class="calth">__title__</th>\
</tr>\
<tr>\
<td class="caltd">Start</td><td class="caltd">__stime__</td>\
</tr>\
<tr>\
<td class="caltd">End</td><td class="caltd">__etime__</td>\
</tr>\
</table>\
<button onclick=\'parent.addFunc("__name__", "__link__")\' style="width:50%">Add to Calendar</button>'
/*Funktion fügt Buttons zu Anhängen hinzu, die das Dateiformat .ICS haben.*/
function addButtons()
{
try{
var infos = getFileInfo();
var names = infos[0];
var links = infos[1];
var rainloopFrame = document.getElementById("rliframe");
var mailtops = rainloopFrame.contentDocument.querySelectorAll('[data-x-div-type=html]');
for (let n=0; n<mailtops.length; n++){
let mailtop = mailtops[n];
if(mailtop.innerHTML.indexOf("<div id=\"endCalenderTable\"></div>")==-1){
var newHtml = "";
for(let i=0; i<names.length; i++){
let name=names[i];
let dlLink=links[i];
let responseText = httpGet(dlLink);
let parsedTitle = getTitle(responseText);
let parsedStartTime = getStart(responseText);
let parsedEndTime = getEnd(responseText);
let tmp = tableHtml.replace("__title__", parsedTitle);
tmp = tmp.replace("__stime__", timeString(parsedStartTime));
tmp = tmp.replace("__etime__", timeString(parsedEndTime));
tmp = tmp.replace("__name__", name);
tmp = tmp.replace("__link__", dlLink);
newHtml += tmp;
}
mailtop.innerHTML = tableStyle + newHtml + "<div id=\"endCalenderTable\"></div>" + mailtop.innerHTML;
}
}
}
catch(e){}
}
setInterval(addButtons, 1000);`